Micron Document
🎖️GitЯра🎖️


Displaying Raw • Download

androidApp/src/google/kotlin/org/meshtastic/app/map/MapView.kt renovate/fastlane-2.x-lockfile (056eed64) Text, 89.39 KB

T8b949e/*
* Copyright (c) 2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Tf0883e@fileTb4b4b4:Te6edf3SuppressTb4b4b4(Ta5d6ff"Ta5d6ffMagicNumberTa5d6ff"Tb4b4b4)

Tff7b72package T7ee787org.meshtastic.app.map

Tff7b72import T7ee787android.annotation.SuppressLint
Tff7b72import T7ee787android.app.Activity
Tff7b72import T7ee787android.content.Intent
Tff7b72import T7ee787android.graphics.Bitmap
Tff7b72import T7ee787android.location.Location
Tff7b72import T7ee787androidx.activity.compose.rememberLauncherForActivityResult
Tff7b72import T7ee787androidx.activity.result.contract.ActivityResultContracts
Tff7b72import T7ee787androidx.appcompat.app.AppCompatDelegate
Tff7b72import T7ee787androidx.compose.foundation.background
Tff7b72import T7ee787androidx.compose.foundation.border
Tff7b72import T7ee787androidx.compose.foundation.isSystemInDarkTheme
Tff7b72import T7ee787androidx.compose.foundation.layout.Box
Tff7b72import T7ee787androidx.compose.foundation.layout.Column
Tff7b72import T7ee787androidx.compose.foundation.layout.Row
Tff7b72import T7ee787androidx.compose.foundation.layout.Spacer
Tff7b72import T7ee787androidx.compose.foundation.layout.fillMaxSize
Tff7b72import T7ee787androidx.compose.foundation.layout.padding
Tff7b72import T7ee787androidx.compose.foundation.layout.size
Tff7b72import T7ee787androidx.compose.foundation.layout.width
Tff7b72import T7ee787androidx.compose.foundation.shape.CircleShape
Tff7b72import T7ee787androidx.compose.material3.Button
Tff7b72import T7ee787androidx.compose.material3.Card
Tff7b72import T7ee787androidx.compose.material3.ExperimentalMaterial3Api
Tff7b72import T7ee787androidx.compose.material3.HorizontalDivider
Tff7b72import T7ee787androidx.compose.material3.Icon
Tff7b72import T7ee787androidx.compose.material3.MaterialTheme
Tff7b72import T7ee787androidx.compose.material3.ModalBottomSheet
Tff7b72import T7ee787androidx.compose.material3.Text
Tff7b72import T7ee787androidx.compose.material3.TextButton
Tff7b72import T7ee787androidx.compose.runtime.Composable
Tff7b72import T7ee787androidx.compose.runtime.DisposableEffect
Tff7b72import T7ee787androidx.compose.runtime.LaunchedEffect
Tff7b72import T7ee787androidx.compose.runtime.getValue
Tff7b72import T7ee787androidx.compose.runtime.key
Tff7b72import T7ee787androidx.compose.runtime.mutableStateOf
Tff7b72import T7ee787androidx.compose.runtime.remember
Tff7b72import T7ee787androidx.compose.runtime.rememberCoroutineScope
Tff7b72import T7ee787androidx.compose.runtime.setValue
Tff7b72import T7ee787androidx.compose.ui.Alignment
Tff7b72import T7ee787androidx.compose.ui.Modifier
Tff7b72import T7ee787androidx.compose.ui.graphics.Color
Tff7b72import T7ee787androidx.compose.ui.platform.LocalContext
Tff7b72import T7ee787androidx.compose.ui.unit.dp
Tff7b72import T7ee787androidx.lifecycle.compose.collectAsStateWithLifecycle
Tff7b72import T7ee787co.touchlab.kermit.Logger
Tff7b72import T7ee787com.google.android.gms.location.FusedLocationProviderClient
Tff7b72import T7ee787com.google.android.gms.location.LocationCallback
Tff7b72import T7ee787com.google.android.gms.location.LocationRequest
Tff7b72import T7ee787com.google.android.gms.location.LocationResult
Tff7b72import T7ee787com.google.android.gms.location.LocationServices
Tff7b72import T7ee787com.google.android.gms.location.Priority
Tff7b72import T7ee787com.google.android.gms.maps.CameraUpdateFactory
Tff7b72import T7ee787com.google.android.gms.maps.model.BitmapDescriptorFactory
Tff7b72import T7ee787com.google.android.gms.maps.model.CameraPosition
Tff7b72import T7ee787com.google.android.gms.maps.model.GroundOverlay
Tff7b72import T7ee787com.google.android.gms.maps.model.GroundOverlayOptions
Tff7b72import T7ee787com.google.android.gms.maps.model.JointType
Tff7b72import T7ee787com.google.android.gms.maps.model.LatLng
Tff7b72import T7ee787com.google.android.gms.maps.model.LatLngBounds
Tff7b72import T7ee787com.google.maps.android.SphericalUtil
Tff7b72import T7ee787com.google.maps.android.compose.CameraPositionState
Tff7b72import T7ee787com.google.maps.android.compose.Circle
Tff7b72import T7ee787com.google.maps.android.compose.ComposeMapColorScheme
Tff7b72import T7ee787com.google.maps.android.compose.GoogleMap
Tff7b72import T7ee787com.google.maps.android.compose.MapEffect
Tff7b72import T7ee787com.google.maps.android.compose.MapProperties
Tff7b72import T7ee787com.google.maps.android.compose.MapType
Tff7b72import T7ee787com.google.maps.android.compose.MapUiSettings
Tff7b72import T7ee787com.google.maps.android.compose.MapsComposeExperimentalApi
Tff7b72import T7ee787com.google.maps.android.compose.MarkerComposable
Tff7b72import T7ee787com.google.maps.android.compose.MarkerInfoWindowComposable
Tff7b72import T7ee787com.google.maps.android.compose.Polygon
Tff7b72import T7ee787com.google.maps.android.compose.Polyline
Tff7b72import T7ee787com.google.maps.android.compose.TileOverlay
Tff7b72import T7ee787com.google.maps.android.compose.rememberCameraPositionState
Tff7b72import T7ee787com.google.maps.android.compose.rememberUpdatedMarkerState
Tff7b72import T7ee787com.google.maps.android.compose.widgets.ScaleBar
Tff7b72import T7ee787com.google.maps.android.data.parser.geojson.GeoJsonParser
Tff7b72import T7ee787com.google.maps.android.data.renderer.UrlIconProvider
Tff7b72import T7ee787com.google.maps.android.data.renderer.mapper.toLayer
Tff7b72import T7ee787com.google.maps.android.data.renderer.mapview.MapViewRenderer
Tff7b72import T7ee787com.google.maps.android.data.renderer.model.DataLayer
Tff7b72import T7ee787com.google.maps.android.data.renderer.model.Feature
Tff7b72import T7ee787com.google.maps.android.data.renderer.model.Geometry
Tff7b72import T7ee787com.google.maps.android.data.renderer.model.LineString
Tff7b72import T7ee787com.google.maps.android.data.renderer.model.LineStyle
Tff7b72import T7ee787com.google.maps.android.data.renderer.model.MultiGeometry
Tff7b72import T7ee787com.google.maps.android.data.renderer.model.PointGeometry
Tff7b72import T7ee787com.google.maps.android.data.renderer.model.PointStyle
Tff7b72import T7ee787com.google.maps.android.data.renderer.model.PolygonStyle
Tff7b72import T7ee787kotlinx.coroutines.CancellationException
Tff7b72import T7ee787kotlinx.coroutines.CoroutineScope
Tff7b72import T7ee787kotlinx.coroutines.Dispatchers
Tff7b72import T7ee787kotlinx.coroutines.delay
Tff7b72import T7ee787kotlinx.coroutines.flow.Flow
Tff7b72import T7ee787kotlinx.coroutines.flow.flow
Tff7b72import T7ee787kotlinx.coroutines.launch
Tff7b72import T7ee787kotlinx.coroutines.suspendCancellableCoroutine
Tff7b72import T7ee787kotlinx.coroutines.withContext
Tff7b72import T7ee787org.jetbrains.compose.resources.stringResource
Tff7b72import T7ee787org.koin.compose.viewmodel.koinViewModel
Tff7b72import T7ee787org.meshtastic.app.map.component.CustomTileProviderManagerSheet
Tff7b72import T7ee787org.meshtastic.app.map.component.MapTypeDropdown
Tff7b72import T7ee787org.meshtastic.app.map.component.NodeClusterMarkers
Tff7b72import T7ee787org.meshtastic.app.map.component.WaypointMarkers
Tff7b72import T7ee787org.meshtastic.app.map.model.NodeClusterItem
Tff7b72import T7ee787org.meshtastic.app.map.offline.pmtiles.OfflineRegionExtractor
Tff7b72import T7ee787org.meshtastic.app.map.offline.pmtiles.OfflineVectorOverlay
Tff7b72import T7ee787org.meshtastic.app.map.offline.pmtiles.component.OfflineRegionManagerSection
Tff7b72import T7ee787org.meshtastic.app.map.offline.terrain.ContourOverlay
Tff7b72import T7ee787org.meshtastic.app.map.offline.terrain.HillshadeTileProvider
Tff7b72import T7ee787org.meshtastic.app.map.tiles.RasterBasemap
Tff7b72import T7ee787org.meshtastic.core.common.util.MeasurementSystem
Tff7b72import T7ee787org.meshtastic.core.common.util.nowSeconds
Tff7b72import T7ee787org.meshtastic.core.model.Node
Tff7b72import T7ee787org.meshtastic.core.model.TracerouteOverlay
Tff7b72import T7ee787org.meshtastic.core.model.geofence.toGeofence
Tff7b72import T7ee787org.meshtastic.core.model.isLocked
Tff7b72import T7ee787org.meshtastic.core.model.isModifiableBy
Tff7b72import T7ee787org.meshtastic.core.model.util.GeoConstants.DEG_D
Tff7b72import T7ee787org.meshtastic.core.model.util.GeoConstants.HEADING_DEG
Tff7b72import T7ee787org.meshtastic.core.model.util.isValidCodePoint
Tff7b72import T7ee787org.meshtastic.core.model.util.kmhIn
Tff7b72import T7ee787org.meshtastic.core.model.util.metersIn
Tff7b72import T7ee787org.meshtastic.core.model.util.toCodePointString
Tff7b72import T7ee787org.meshtastic.core.model.util.toString
Tff7b72import T7ee787org.meshtastic.core.model.util.waypointIconOrDefault
Tff7b72import T7ee787org.meshtastic.core.resources.Res
Tff7b72import T7ee787org.meshtastic.core.resources.alt
Tff7b72import T7ee787org.meshtastic.core.resources.cancel
Tff7b72import T7ee787org.meshtastic.core.resources.geofence_box_author_hint
Tff7b72import T7ee787org.meshtastic.core.resources.geofence_box_use_view
Tff7b72import T7ee787org.meshtastic.core.resources.heading
Tff7b72import T7ee787org.meshtastic.core.resources.latitude
Tff7b72import T7ee787org.meshtastic.core.resources.longitude
Tff7b72import T7ee787org.meshtastic.core.resources.manage_map_layers
Tff7b72import T7ee787org.meshtastic.core.resources.map_tile_source
Tff7b72import T7ee787org.meshtastic.core.resources.now
Tff7b72import T7ee787org.meshtastic.core.resources.position
Tff7b72import T7ee787org.meshtastic.core.resources.sats
Tff7b72import T7ee787org.meshtastic.core.resources.speed
Tff7b72import T7ee787org.meshtastic.core.resources.speed_kmh
Tff7b72import T7ee787org.meshtastic.core.resources.speed_mph
Tff7b72import T7ee787org.meshtastic.core.resources.timestamp
Tff7b72import T7ee787org.meshtastic.core.resources.track_point
Tff7b72import T7ee787org.meshtastic.core.resources.unknown
Tff7b72import T7ee787org.meshtastic.core.ui.component.NodeChip
Tff7b72import T7ee787org.meshtastic.core.ui.icon.Layers
Tff7b72import T7ee787org.meshtastic.core.ui.icon.Map
Tff7b72import T7ee787org.meshtastic.core.ui.icon.MeshtasticIcons
Tff7b72import T7ee787org.meshtastic.core.ui.icon.TripOrigin
Tff7b72import T7ee787org.meshtastic.core.ui.theme.TracerouteColors
Tff7b72import T7ee787org.meshtastic.core.ui.util.ActiveWhileStarted
Tff7b72import T7ee787org.meshtastic.core.ui.util.KeepScreenOn
Tff7b72import T7ee787org.meshtastic.core.ui.util.PermissionStatus
Tff7b72import T7ee787org.meshtastic.core.ui.util.formatAgo
Tff7b72import T7ee787org.meshtastic.core.ui.util.formatPositionTime
Tff7b72import T7ee787org.meshtastic.core.ui.util.rememberLocationPermissionState
Tff7b72import T7ee787org.meshtastic.feature.map.BaseMapViewModel.MapFilterState
Tff7b72import T7ee787org.meshtastic.feature.map.MapBounds
Tff7b72import T7ee787org.meshtastic.feature.map.MapNodePolicy
Tff7b72import T7ee787org.meshtastic.feature.map.component.ClusterMemberEntry
Tff7b72import T7ee787org.meshtastic.feature.map.component.ClusterMembersDialog
Tff7b72import T7ee787org.meshtastic.feature.map.component.CustomMapLayersSheet
Tff7b72import T7ee787org.meshtastic.feature.map.component.DeleteWaypointDialog
Tff7b72import T7ee787org.meshtastic.feature.map.component.EditWaypointDialog
Tff7b72import T7ee787org.meshtastic.feature.map.component.MapButton
Tff7b72import T7ee787org.meshtastic.feature.map.component.MapControlsOverlay
Tff7b72import T7ee787org.meshtastic.feature.map.component.MapFilterSheet
Tff7b72import T7ee787org.meshtastic.feature.map.component.NodeTrackFilterMenu
Tff7b72import T7ee787org.meshtastic.feature.map.component.OfflineStatusBanner
Tff7b72import T7ee787org.meshtastic.feature.map.component.RasterOverlayToggles
Tff7b72import T7ee787org.meshtastic.feature.map.component.SitePlannerLaunch
Tff7b72import T7ee787org.meshtastic.feature.map.component.WaypointInfoDialog
Tff7b72import T7ee787org.meshtastic.feature.map.component.mapFilterActions
Tff7b72import T7ee787org.meshtastic.feature.map.component.toSitePlannerParams
Tff7b72import T7ee787org.meshtastic.feature.map.geojson.sanitizeImportedIconUrl
Tff7b72import T7ee787org.meshtastic.feature.map.includes
Tff7b72import T7ee787org.meshtastic.feature.map.kml.ICON_URL_PROPERTY
Tff7b72import T7ee787org.meshtastic.feature.map.kml.KmlGroundOverlay
Tff7b72import T7ee787org.meshtastic.feature.map.layers.LayerType
Tff7b72import T7ee787org.meshtastic.feature.map.layers.MapLayerItem
Tff7b72import T7ee787org.meshtastic.feature.map.layers.opacityOf
Tff7b72import T7ee787org.meshtastic.feature.map.layers.toPickedMapFile
Tff7b72import T7ee787org.meshtastic.feature.map.terrain.MapterhornEndpoints
Tff7b72import T7ee787org.meshtastic.feature.map.tiles.mapAttributionText
Tff7b72import T7ee787org.meshtastic.feature.map.tracerouteNodeSelection
Tff7b72import T7ee787org.meshtastic.proto.BoundingBox
Tff7b72import T7ee787org.meshtastic.proto.Position
Tff7b72import T7ee787org.meshtastic.proto.Waypoint
Tff7b72import T7ee787java.io.BufferedInputStream
Tff7b72import T7ee787java.io.ByteArrayInputStream
Tff7b72import T7ee787java.io.InputStream
Tff7b72import T7ee787kotlin.coroutines.resume
Tff7b72import T7ee787kotlin.math.abs
Tff7b72import T7ee787kotlin.math.max
Tff7b72import T7ee787kotlin.math.roundToInt
Tff7b72import T7ee787android.graphics.Color Tff7b72as Te6edf3AndroidColor
Tff7b72import T7ee787com.google.android.gms.maps.GoogleMap Tff7b72as Te6edf3GmsGoogleMap
Tff7b72import T7ee787com.google.maps.android.data.renderer.model.Polygon Tff7b72as Te6edf3ModelPolygon

T8b949e// region --- Map Mode ---

T8b949e/**
* Discriminated mode for [MapView] — replaces the original pile of nullable parameters with a type-safe sealed
* hierarchy. Each mode carries only the data it needs; the shared infrastructure (location tracking, tile providers,
* controls overlay) is available in every mode.
*/
Tff7b72sealed Tff7b72interface T56d364GoogleMapMode Tb4b4b4{
T8b949e/** Standard map: node clusters, waypoints, custom layers, waypoint editing. */
Tff7b72data Tff7b72object T56d364Main Tb4b4b4: Te6edf3GoogleMapMode

T8b949e/** Focused node position track: polyline + gradient markers for historical positions. */
Tff7b72data Tff7b72class T56d364NodeTrackTb4b4b4(
Tff7b72val Te6edf3focusedNodeTb4b4b4: Te6edf3Node?Tb4b4b4,
Tff7b72val Te6edf3positionsTb4b4b4: Te6edf3ListTff7b72<Te6edf3PositionTff7b72>Tb4b4b4,
Tff7b72val Te6edf3selectedPositionTimeTb4b4b4: Tffa657Int? Tff7b72= Tff7b72nullTb4b4b4,
Tff7b72val Te6edf3onPositionSelectedTb4b4b4: Tb4b4b4(Tb4b4b4(Tffa657IntTb4b4b4) Tff7b72-Tff7b72> Tffa657UnitTb4b4b4)Tff7b72? Tff7b72= Tff7b72nullTb4b4b4,
Tb4b4b4) Tb4b4b4: Te6edf3GoogleMapMode

T8b949e/** Traceroute visualization: offset forward/return polylines + hop markers. */
Tff7b72data Tff7b72class T56d364TracerouteTb4b4b4(
Tff7b72val Te6edf3overlayTb4b4b4: Te6edf3TracerouteOverlay?Tb4b4b4,
Tff7b72val Te6edf3nodePositionsTb4b4b4: Te6edf3MapTff7b72<Tffa657IntTb4b4b4, Te6edf3PositionTff7b72>Tb4b4b4,
Tff7b72val Te6edf3onMappableCountChangedTb4b4b4: Tb4b4b4(Te6edf3shownTb4b4b4: Tffa657IntTb4b4b4, Te6edf3totalTb4b4b4: Tffa657IntTb4b4b4) Tff7b72-Tff7b72> Tffa657UnitTb4b4b4,
Tb4b4b4) Tb4b4b4: Te6edf3GoogleMapMode
Tb4b4b4}

T8b949e// endregion

Tff7b72private Tff7b72const Tff7b72val Te6edf3TRACEROUTE_OFFSET_METERS Tff7b72= T79c0ff1T79c0ff0T79c0ff0.0
Tff7b72private Tff7b72const Tff7b72val Te6edf3TRACEROUTE_BOUNDS_PADDING_PX Tff7b72= T79c0ff1T79c0ff2T79c0ff0

T8b949e// Shared geofence overlay styling (orange, matching the fdroid flavor).
Tff7b72private Tff7b72val Te6edf3GEOFENCE_OVERLAY_COLOR Tff7b72= Te6edf3ColorTb4b4b4(T79c0ff0Te6edf3xFFFF9800Tb4b4b4)
Tff7b72private Tff7b72const Tff7b72val Te6edf3GEOFENCE_FILL_ALPHA Tff7b72= T79c0ff0.12f
Tff7b72private Tff7b72const Tff7b72val Te6edf3GEOFENCE_STROKE_WIDTH Tff7b72= T79c0ff2f

T8b949e// simplestyle-spec fallbacks for imported GeoJSON overlays that omit these keys; tune here.
T8b949e// 0.35 lets stacked contour bands read as a gradient.
Tff7b72private Tff7b72const Tff7b72val Te6edf3DEFAULT_GEOJSON_FILL_OPACITY Tff7b72= T79c0ff0.35f
Tff7b72private Tff7b72const Tff7b72val Te6edf3DEFAULT_GEOJSON_STROKE_WIDTH Tff7b72= T79c0ff2f

T8b949e// Minimum lat/lon delta (~11 m) between the two box-authoring corner taps; below this the box would be degenerate
T8b949e// (zero-area) so the second tap is ignored.
Tff7b72private Tff7b72const Tff7b72val Te6edf3BOX_AUTHORING_MIN_CORNER_DELTA Tff7b72= T79c0ff1e-4

T8b949e/** Above the raster basemap at -1, below every marker and shape the mesh draws at 0 and up. */
Tff7b72private Tff7b72const Tff7b72val Te6edf3OVERLAY_Z_INDEX Tff7b72= Tff7b72-T79c0ff0.5f

T8b949e/** Below the offline vector layer's own water/roads/boundaries (-0.75f) so those still draw on top of the shading. */
Tff7b72private Tff7b72const Tff7b72val Te6edf3TERRAIN_HILLSHADE_Z_INDEX Tff7b72= Tff7b72-T79c0ff0.9f

T8b949e/** Clears Google's own logo and the zoom controls, both of which sit along the bottom edge. */
Tff7b72private Tff7b72val Te6edf3ATTRIBUTION_BOTTOM_PADDING Tff7b72= T79c0ff4.Te6edf3dp
Tff7b72private Tff7b72const Tff7b72val Te6edf3ATTRIBUTION_SCRIM_ALPHA Tff7b72= T79c0ff0.7f

Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffCyclomaticComplexMethodTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffLongMethodTa5d6ff"Tb4b4b4)
Tf0883e@OptInTb4b4b4(Te6edf3MapsComposeExperimentalApiTff7b72::Te6edf3classTb4b4b4, Te6edf3ExperimentalMaterial3ApiTff7b72::Te6edf3classTb4b4b4)
Tf0883e@Composable
Tff7b72fun Td2a8ffMapViewTb4b4b4(
Te6edf3modifierTb4b4b4: Te6edf3Modifier Tff7b72= Te6edf3ModifierTb4b4b4,
Te6edf3mapViewModelTb4b4b4: Te6edf3MapViewModel Tff7b72= Te6edf3koinViewModelTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3navigateToNodeDetailsTb4b4b4: Tb4b4b4(Tffa657IntTb4b4b4) Tff7b72-Tff7b72> Tffa657Unit Tff7b72= Tb4b4b4{Tb4b4b4}Tb4b4b4,
Te6edf3modeTb4b4b4: Te6edf3GoogleMapMode Tff7b72= Te6edf3GoogleMapModeTb4b4b4.Te6edf3MainTb4b4b4,
Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3context Tff7b72= Te6edf3LocalContextTb4b4b4.Te6edf3current
Tff7b72val Te6edf3coroutineScope Tff7b72= Te6edf3rememberCoroutineScopeTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3mapLayers Tff7b72by Te6edf3mapViewModelTb4b4b4.Te6edf3mapLayersTb4b4b4.Te6edf3collectAsStateWithLifecycleTb4b4b4(Tb4b4b4)

T8b949e// --- Location permissions ---
Tff7b72val Te6edf3locationPermission Tff7b72= Te6edf3rememberLocationPermissionStateTb4b4b4(Tb4b4b4)
Tff7b72var Te6edf3triggerLocationToggleAfterPermission Tff7b72by Te6edf3remember Tb4b4b4{ Te6edf3mutableStateOfTb4b4b4(Tff7b72falseTb4b4b4) Tb4b4b4}

T8b949e// --- Location tracking ---
Tff7b72var Te6edf3isLocationTrackingEnabled Tff7b72by Te6edf3remember Tb4b4b4{ Te6edf3mutableStateOfTb4b4b4(Tff7b72falseTb4b4b4) Tb4b4b4}
Tff7b72var Te6edf3followPhoneBearing Tff7b72by Te6edf3remember Tb4b4b4{ Te6edf3mutableStateOfTb4b4b4(Tff7b72falseTb4b4b4) Tb4b4b4}

Te6edf3LaunchedEffectTb4b4b4(Te6edf3locationPermissionTb4b4b4.Te6edf3isGrantedTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3locationPermissionTb4b4b4.Te6edf3isGranted Tff7b72&Tff7b72& Te6edf3triggerLocationToggleAfterPermissionTb4b4b4) Tb4b4b4{
Te6edf3isLocationTrackingEnabled Tff7b72= Tff7b72true
Te6edf3triggerLocationToggleAfterPermission Tff7b72= Tff7b72false
Tb4b4b4}
Tb4b4b4}

T8b949e// --- File picker for map layers (Main mode) ---
Tff7b72val Te6edf3filePickerLauncher Tff7b72=
Te6edf3rememberLauncherForActivityResultTb4b4b4(Te6edf3contract Tff7b72= Te6edf3ActivityResultContractsTb4b4b4.Te6edf3StartActivityForResultTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4{ Te6edf3result Tff7b72-Tff7b72>
Tff7b72if Tb4b4b4(Te6edf3resultTb4b4b4.Te6edf3resultCode Tff7b72=Tff7b72= Te6edf3ActivityTb4b4b4.Te6edf3RESULT_OKTb4b4b4) Tb4b4b4{
Te6edf3resultTb4b4b4.Te6edf3dataTff7b72?.Te6edf3dataTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3uri Tff7b72-Tff7b72> Te6edf3mapViewModelTb4b4b4.Te6edf3addMapLayerTb4b4b4(Te6edf3uriTb4b4b4.Te6edf3toPickedMapFileTb4b4b4(Te6edf3contextTb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

T8b949e// --- UI state ---
Tff7b72var Te6edf3mapFilterMenuExpanded Tff7b72by Te6edf3remember Tb4b4b4{ Te6edf3mutableStateOfTb4b4b4(Tff7b72falseTb4b4b4) Tb4b4b4}
Tff7b72val Te6edf3mapFilterState Tff7b72by Te6edf3mapViewModelTb4b4b4.Te6edf3mapFilterStateFlowTb4b4b4.Te6edf3collectAsStateWithLifecycleTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3ourNodeInfo Tff7b72by Te6edf3mapViewModelTb4b4b4.Te6edf3ourNodeInfoTb4b4b4.Te6edf3collectAsStateWithLifecycleTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3channelSet Tff7b72by Te6edf3mapViewModelTb4b4b4.Te6edf3channelSetTb4b4b4.Te6edf3collectAsStateWithLifecycleTb4b4b4(Tb4b4b4)
Tff7b72var Te6edf3editingWaypoint Tff7b72by Te6edf3remember Tb4b4b4{ Te6edf3mutableStateOfTff7b72<Te6edf3Waypoint?Tff7b72>Tb4b4b4(Tff7b72nullTb4b4b4) Tb4b4b4}
Tff7b72var Te6edf3deletingWaypoint Tff7b72by Te6edf3remember Tb4b4b4{ Te6edf3mutableStateOfTff7b72<Te6edf3Waypoint?Tff7b72>Tb4b4b4(Tff7b72nullTb4b4b4) Tb4b4b4}
Tff7b72var Te6edf3geofenceInfoWaypoint Tff7b72by Te6edf3remember Tb4b4b4{ Te6edf3mutableStateOfTff7b72<Te6edf3Waypoint?Tff7b72>Tb4b4b4(Tff7b72nullTb4b4b4) Tb4b4b4}
Tff7b72val Te6edf3displayUnits Tff7b72by Te6edf3mapViewModelTb4b4b4.Te6edf3displayUnitsTb4b4b4.Te6edf3collectAsStateWithLifecycleTb4b4b4(Tb4b4b4)

T8b949e// --- Geofence box authoring (Main mode) ---
T8b949e// When non-null, the user is defining a bounding box for [boxAuthoringDraft] by tapping two corners.
Tff7b72var Te6edf3boxAuthoringDraft Tff7b72by Te6edf3remember Tb4b4b4{ Te6edf3mutableStateOfTff7b72<Te6edf3Waypoint?Tff7b72>Tb4b4b4(Tff7b72nullTb4b4b4) Tb4b4b4}
Tff7b72var Te6edf3boxAuthoringFirstCorner Tff7b72by Te6edf3remember Tb4b4b4{ Te6edf3mutableStateOfTff7b72<Te6edf3LatLng?Tff7b72>Tb4b4b4(Tff7b72nullTb4b4b4) Tb4b4b4}
Tff7b72var Te6edf3boxAuthoringSecondCorner Tff7b72by Te6edf3remember Tb4b4b4{ Te6edf3mutableStateOfTff7b72<Te6edf3LatLng?Tff7b72>Tb4b4b4(Tff7b72nullTb4b4b4) Tb4b4b4}

Tff7b72val Te6edf3selectedGoogleMapType Tff7b72by Te6edf3mapViewModelTb4b4b4.Te6edf3selectedGoogleMapTypeTb4b4b4.Te6edf3collectAsStateWithLifecycleTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3currentRasterBasemap Tff7b72by Te6edf3mapViewModelTb4b4b4.Te6edf3selectedRasterBasemapTb4b4b4.Te6edf3collectAsStateWithLifecycleTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3offlineOverlayEnabled Tff7b72by Te6edf3mapViewModelTb4b4b4.Te6edf3offlineOverlayEnabledTb4b4b4.Te6edf3collectAsStateWithLifecycleTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3terrainHillshadeEnabled Tff7b72by Te6edf3mapViewModelTb4b4b4.Te6edf3terrainHillshadeEnabledTb4b4b4.Te6edf3collectAsStateWithLifecycleTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3terrainContoursEnabled Tff7b72by Te6edf3mapViewModelTb4b4b4.Te6edf3terrainContoursEnabledTb4b4b4.Te6edf3collectAsStateWithLifecycleTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3mapNetworkAvailable Tff7b72by Te6edf3mapViewModelTb4b4b4.Te6edf3mapNetworkAvailableTb4b4b4.Te6edf3collectAsStateWithLifecycleTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3enabledOverlayIds Tff7b72by Te6edf3mapViewModelTb4b4b4.Te6edf3enabledOverlayIdsTb4b4b4.Te6edf3collectAsStateWithLifecycleTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3layerOpacity Tff7b72by Te6edf3mapViewModelTb4b4b4.Te6edf3layerOpacityTb4b4b4.Te6edf3collectAsStateWithLifecycleTb4b4b4(Tb4b4b4)

Tff7b72var Te6edf3mapTypeMenuExpanded Tff7b72by Te6edf3remember Tb4b4b4{ Te6edf3mutableStateOfTb4b4b4(Tff7b72falseTb4b4b4) Tb4b4b4}
Tff7b72var Te6edf3showCustomTileManagerSheet Tff7b72by Te6edf3remember Tb4b4b4{ Te6edf3mutableStateOfTb4b4b4(Tff7b72falseTb4b4b4) Tb4b4b4}

T8b949e// --- Camera ---
T8b949e// Main mode persists camera; NodeTrack/Traceroute use ephemeral state with auto-centering.
Tff7b72val Te6edf3cameraPositionState Tff7b72=
Tff7b72if Tb4b4b4(Te6edf3mode Tff7b72is Te6edf3GoogleMapModeTb4b4b4.Te6edf3MainTb4b4b4) Te6edf3mapViewModelTb4b4b4.Te6edf3cameraPositionState Tff7b72else Te6edf3rememberCameraPositionStateTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3cameraInitialization Tff7b72by Te6edf3mapViewModelTb4b4b4.Te6edf3cameraInitializationTb4b4b4.Te6edf3collectAsStateWithLifecycleTb4b4b4(Tb4b4b4)
Tff7b72var Te6edf3isMapLoaded Tff7b72by Te6edf3remember Tb4b4b4{ Te6edf3mutableStateOfTb4b4b4(Tff7b72falseTb4b4b4) Tb4b4b4}

Tff7b72if Tb4b4b4(Te6edf3mode Tff7b72is Te6edf3GoogleMapModeTb4b4b4.Te6edf3MainTb4b4b4) Tb4b4b4{
Te6edf3LaunchedEffectTb4b4b4(Te6edf3cameraPositionStateTb4b4b4.Te6edf3isMovingTb4b4b4, Te6edf3cameraInitializationTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3cameraPositionStateTb4b4b4.Te6edf3isMoving Tff7b72&Tff7b72& Te6edf3cameraInitialization Tff7b72=Tff7b72= Te6edf3CameraInitializationTb4b4b4.Te6edf3RestoredTb4b4b4) Tb4b4b4{
Te6edf3mapViewModelTb4b4b4.Te6edf3saveCameraPositionTb4b4b4(Te6edf3cameraPositionStateTb4b4b4.Te6edf3positionTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

T8b949e// --- FusedLocation ---
Tff7b72val Te6edf3fusedLocationClient Tff7b72= Te6edf3remember Tb4b4b4{ Te6edf3LocationServicesTb4b4b4.Te6edf3getFusedLocationProviderClientTb4b4b4(Te6edf3contextTb4b4b4) Tb4b4b4}
Tff7b72val Te6edf3locationCallback Tff7b72= Te6edf3remember Tb4b4b4{
Tff7b72object Tb4b4b4: T56d364LocationCallbackTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72override Tff7b72fun Td2a8ffonLocationResultTb4b4b4(Te6edf3locationResultTb4b4b4: Te6edf3LocationResultTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3isLocationTrackingEnabledTb4b4b4) Tb4b4b4{
Te6edf3locationResultTb4b4b4.Te6edf3lastLocationTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3location Tff7b72-Tff7b72>
Tff7b72val Te6edf3latLng Tff7b72= Te6edf3LatLngTb4b4b4(Te6edf3locationTb4b4b4.Te6edf3latitudeTb4b4b4, Te6edf3locationTb4b4b4.Te6edf3longitudeTb4b4b4)
Tff7b72val Te6edf3cameraUpdate Tff7b72=
Tff7b72if Tb4b4b4(Te6edf3followPhoneBearingTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3bearing Tff7b72=
Tff7b72if Tb4b4b4(Te6edf3locationTb4b4b4.Te6edf3hasBearingTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3locationTb4b4b4.Te6edf3bearing
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3cameraPositionStateTb4b4b4.Te6edf3positionTb4b4b4.Te6edf3bearing
Tb4b4b4}
Te6edf3CameraUpdateFactoryTb4b4b4.Te6edf3newCameraPositionTb4b4b4(
Te6edf3CameraPositionTb4b4b4.Te6edf3BuilderTb4b4b4(Tb4b4b4)
Tb4b4b4.Te6edf3targetTb4b4b4(Te6edf3latLngTb4b4b4)
Tb4b4b4.Te6edf3zoomTb4b4b4(Te6edf3cameraPositionStateTb4b4b4.Te6edf3positionTb4b4b4.Te6edf3zoomTb4b4b4)
Tb4b4b4.Te6edf3bearingTb4b4b4(Te6edf3bearingTb4b4b4)
Tb4b4b4.Te6edf3buildTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3CameraUpdateFactoryTb4b4b4.Te6edf3newLatLngZoomTb4b4b4(Te6edf3latLngTb4b4b4, Te6edf3cameraPositionStateTb4b4b4.Te6edf3positionTb4b4b4.Te6edf3zoomTb4b4b4)
Tb4b4b4}
Te6edf3coroutineScopeTb4b4b4.Te6edf3launch Tb4b4b4{
Tff7b72try Tb4b4b4{
Te6edf3cameraPositionStateTb4b4b4.Te6edf3animateTb4b4b4(Te6edf3cameraUpdateTb4b4b4)
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3IllegalStateExceptionTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3d Tb4b4b4{ Ta5d6ff"Ta5d6ffError animating camera to location: Tffd700${Te6edf3eTb4b4b4.Te6edf3messageTffd700}Ta5d6ff" Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Te6edf3ActiveWhileStartedTb4b4b4(Te6edf3enabled Tff7b72= Te6edf3isLocationTrackingEnabled Tff7b72&Tff7b72& Te6edf3locationPermissionTb4b4b4.Te6edf3isGrantedTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3locationRequest Tff7b72=
Te6edf3LocationRequestTb4b4b4.Te6edf3BuilderTb4b4b4(Te6edf3PriorityTb4b4b4.Te6edf3PRIORITY_HIGH_ACCURACYTb4b4b4, T79c0ff5T79c0ff0T79c0ff0T79c0ff0LTb4b4b4)Tb4b4b4.Te6edf3setMinUpdateIntervalMillisTb4b4b4(T79c0ff2T79c0ff0T79c0ff0T79c0ff0LTb4b4b4)Tb4b4b4.Te6edf3buildTb4b4b4(Tb4b4b4)
Tff7b72try Tb4b4b4{
Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffMissingPermissionTa5d6ff"Tb4b4b4)
Te6edf3fusedLocationClientTb4b4b4.Te6edf3requestLocationUpdatesTb4b4b4(Te6edf3locationRequestTb4b4b4, Te6edf3locationCallbackTb4b4b4, Tff7b72nullTb4b4b4)
Te6edf3LoggerTb4b4b4.Te6edf3d Tb4b4b4{ Ta5d6ff"Ta5d6ffStarted location trackingTa5d6ff" Tb4b4b4}
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3SecurityExceptionTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3d Tb4b4b4{ Ta5d6ff"Ta5d6ffLocation permission not available: Tffd700${Te6edf3eTb4b4b4.Te6edf3messageTffd700}Ta5d6ff" Tb4b4b4}
Te6edf3isLocationTrackingEnabled Tff7b72= Tff7b72false
Tb4b4b4}

Tff7b72val Te6edf3cleanupTb4b4b4: Tb4b4b4(Tb4b4b4) Tff7b72-Tff7b72> Tffa657Unit Tff7b72= Tb4b4b4{
Te6edf3fusedLocationClientTb4b4b4.Te6edf3removeLocationUpdatesTb4b4b4(Te6edf3locationCallbackTb4b4b4)
Te6edf3LoggerTb4b4b4.Te6edf3d Tb4b4b4{ Ta5d6ff"Ta5d6ffStopped location trackingTa5d6ff" Tb4b4b4}
Tb4b4b4}
Te6edf3cleanup
Tb4b4b4}

T8b949e// --- Node & waypoint data ---
Tff7b72val Te6edf3allNodes Tff7b72by Te6edf3mapViewModelTb4b4b4.Te6edf3nodesWithPositionTb4b4b4.Te6edf3collectAsStateWithLifecycleTb4b4b4(Te6edf3listOfTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3waypoints Tff7b72by Te6edf3mapViewModelTb4b4b4.Te6edf3waypointsTb4b4b4.Te6edf3collectAsStateWithLifecycleTb4b4b4(Te6edf3emptyMapTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3displayableWaypoints Tff7b72= Te6edf3waypointsTb4b4b4.Te6edf3valuesTb4b4b4.Te6edf3mapNotNull Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3waypoint Tb4b4b4}
Tff7b72val Te6edf3selectedWaypointId Tff7b72by Te6edf3mapViewModelTb4b4b4.Te6edf3selectedWaypointIdTb4b4b4.Te6edf3collectAsStateWithLifecycleTb4b4b4(Tb4b4b4)

Tff7b72val Te6edf3filteredNodes Tff7b72= Te6edf3MapNodePolicyTb4b4b4.Te6edf3visibleNodesTb4b4b4(Te6edf3allNodesTb4b4b4, Te6edf3mapFilterStateTb4b4b4, Te6edf3nowSecondsTb4b4b4, Te6edf3ourNodeInfoTff7b72?.Te6edf3numTb4b4b4)

Te6edf3LaunchedEffectTb4b4b4(Te6edf3modeTb4b4b4, Te6edf3cameraInitializationTb4b4b4, Te6edf3isMapLoadedTb4b4b4, Te6edf3filteredNodesTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(
Te6edf3mode Tff7b72is Te6edf3GoogleMapModeTb4b4b4.Te6edf3Main Tff7b72&Tff7b72&
Te6edf3cameraInitialization Tff7b72=Tff7b72= Te6edf3CameraInitializationTb4b4b4.Te6edf3FitNodes Tff7b72&Tff7b72&
Te6edf3isMapLoaded Tff7b72&Tff7b72&
Te6edf3filteredNodesTb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4)
Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3points Tff7b72= Te6edf3filteredNodesTb4b4b4.Te6edf3map Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3positionTb4b4b4.Te6edf3toLatLngTb4b4b4(Tb4b4b4) Tb4b4b4}
Tff7b72val Te6edf3cameraUpdate Tff7b72=
Tff7b72if Tb4b4b4(Te6edf3pointsTb4b4b4.Te6edf3size Tff7b72=Tff7b72= T79c0ff1Tb4b4b4) Tb4b4b4{
Te6edf3CameraUpdateFactoryTb4b4b4.Te6edf3newLatLngZoomTb4b4b4(Te6edf3pointsTb4b4b4.Te6edf3firstTb4b4b4(Tb4b4b4)Tb4b4b4, T79c0ff1T79c0ff2fTb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
T8b949e// Shared with the MapLibre map, which pads a degenerate box rather than handing the camera
T8b949e// something it cannot fit to.
Tff7b72val Te6edf3bounds Tff7b72= Te6edf3MapBoundsTb4b4b4.Te6edf3aroundNodesTb4b4b4(Te6edf3filteredNodesTb4b4b4)Tff7b72?.Te6edf3toLatLngBoundsTb4b4b4(Tb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3bounds Tff7b72=Tff7b72= Tff7b72nullTb4b4b4) Tff7b72returnTf0883e@LaunchedEffect
Te6edf3CameraUpdateFactoryTb4b4b4.Te6edf3newLatLngBoundsTb4b4b4(Te6edf3boundsTb4b4b4, T79c0ff8T79c0ff0Tb4b4b4)
Tb4b4b4}
Te6edf3cameraPositionStateTb4b4b4.Te6edf3moveTb4b4b4(Te6edf3cameraUpdateTb4b4b4)
Te6edf3mapViewModelTb4b4b4.Te6edf3onInitialNodeBoundsAppliedTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4}

Tff7b72val Te6edf3myNodeNum Tff7b72= Te6edf3mapViewModelTb4b4b4.Te6edf3myNodeNum
Tff7b72val Te6edf3relativeTimeBucket Tff7b72= Te6edf3rememberRelativeTimeBucketTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3nodeClusterItems Tff7b72=
Te6edf3rememberNodeClusterItemsTb4b4b4(
Te6edf3nodes Tff7b72= Tff7b72if Tb4b4b4(Te6edf3mode Tff7b72is Te6edf3GoogleMapModeTb4b4b4.Te6edf3MainTb4b4b4) Te6edf3filteredNodes Tff7b72else Te6edf3emptyListTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3myNodeNum Tff7b72= Te6edf3myNodeNumTb4b4b4,
Te6edf3relativeTimeBucket Tff7b72= Te6edf3relativeTimeBucketTb4b4b4,
Tb4b4b4)
Tff7b72val Te6edf3isConnected Tff7b72by Te6edf3mapViewModelTb4b4b4.Te6edf3isConnectedTb4b4b4.Te6edf3collectAsStateWithLifecycleTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3theme Tff7b72by Te6edf3mapViewModelTb4b4b4.Te6edf3themeTb4b4b4.Te6edf3collectAsStateWithLifecycleTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3dark Tff7b72=
Tff7b72when Tb4b4b4(Te6edf3themeTb4b4b4) Tb4b4b4{
Te6edf3AppCompatDelegateTb4b4b4.Te6edf3MODE_NIGHT_YES Tff7b72-Tff7b72> Tff7b72true
Te6edf3AppCompatDelegateTb4b4b4.Te6edf3MODE_NIGHT_NO Tff7b72-Tff7b72> Tff7b72false
Te6edf3AppCompatDelegateTb4b4b4.Te6edf3MODE_NIGHT_FOLLOW_SYSTEM Tff7b72-Tff7b72> Te6edf3isSystemInDarkThemeTb4b4b4(Tb4b4b4)
Tff7b72else Tff7b72-Tff7b72> Te6edf3isSystemInDarkThemeTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tff7b72val Te6edf3mapColorScheme Tff7b72= Tff7b72if Tb4b4b4(Te6edf3darkTb4b4b4) Te6edf3ComposeMapColorSchemeTb4b4b4.Te6edf3DARK Tff7b72else Te6edf3ComposeMapColorSchemeTb4b4b4.Te6edf3LIGHT

T8b949e// --- Mode-specific data ---
T8b949e// Node track: apply time filter
Tff7b72val Te6edf3sortedTrackPositions Tff7b72=
Tff7b72if Tb4b4b4(Te6edf3mode Tff7b72is Te6edf3GoogleMapModeTb4b4b4.Te6edf3NodeTrackTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3lastHeardTrackFilter Tff7b72= Te6edf3mapFilterStateTb4b4b4.Te6edf3lastHeardTrackFilter
Te6edf3rememberTb4b4b4(Te6edf3modeTb4b4b4.Te6edf3positionsTb4b4b4, Te6edf3lastHeardTrackFilterTb4b4b4) Tb4b4b4{
Te6edf3modeTb4b4b4.Te6edf3positionsTb4b4b4.Te6edf3filter Tb4b4b4{ Te6edf3lastHeardTrackFilterTb4b4b4.Te6edf3includesTb4b4b4(Tffa657itTb4b4b4.Te6edf3timeTb4b4b4, Te6edf3nowSecondsTb4b4b4) Tb4b4b4}Tb4b4b4.Te6edf3sortedBy Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3time Tb4b4b4}
Tb4b4b4}
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3emptyListTb4b4b4(Tb4b4b4)
Tb4b4b4}

T8b949e// Traceroute: resolve node selection + polylines. Collected unconditionally per Compose rules
T8b949e// (composable calls cannot be conditional), but only consumed in Traceroute mode. Uses all
T8b949e// nodes, not just those with positions, so getNodeOrFallback can resolve metadata for hops
T8b949e// whose positions come from snapshots.
Tff7b72val Te6edf3allNodesForTraceroute Tff7b72by Te6edf3mapViewModelTb4b4b4.Te6edf3nodesTb4b4b4.Te6edf3collectAsStateWithLifecycleTb4b4b4(Te6edf3listOfTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3tracerouteSelection Tff7b72=
Tff7b72if Tb4b4b4(Te6edf3mode Tff7b72is Te6edf3GoogleMapModeTb4b4b4.Te6edf3TracerouteTb4b4b4) Tb4b4b4{
Te6edf3rememberTb4b4b4(Te6edf3modeTb4b4b4.Te6edf3overlayTb4b4b4, Te6edf3modeTb4b4b4.Te6edf3nodePositionsTb4b4b4, Te6edf3allNodesForTracerouteTb4b4b4) Tb4b4b4{
Te6edf3mapViewModelTb4b4b4.Te6edf3tracerouteNodeSelectionTb4b4b4(
Te6edf3tracerouteOverlay Tff7b72= Te6edf3modeTb4b4b4.Te6edf3overlayTb4b4b4,
Te6edf3tracerouteNodePositions Tff7b72= Te6edf3modeTb4b4b4.Te6edf3nodePositionsTb4b4b4,
Te6edf3nodes Tff7b72= Te6edf3allNodesForTracerouteTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72null
Tb4b4b4}
Tff7b72val Te6edf3tracerouteDisplayNodes Tff7b72= Te6edf3tracerouteSelectionTff7b72?.Te6edf3nodesForMarkers Tff7b72?: Te6edf3emptyListTb4b4b4(Tb4b4b4)

Tff7b72if Tb4b4b4(Te6edf3mode Tff7b72is Te6edf3GoogleMapModeTb4b4b4.Te6edf3TracerouteTb4b4b4) Tb4b4b4{
Te6edf3LaunchedEffectTb4b4b4(Te6edf3modeTb4b4b4.Te6edf3overlayTb4b4b4, Te6edf3tracerouteDisplayNodesTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3modeTb4b4b4.Te6edf3overlay Tff7b72!Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Te6edf3modeTb4b4b4.Te6edf3onMappableCountChangedTb4b4b4(Te6edf3tracerouteDisplayNodesTb4b4b4.Te6edf3sizeTb4b4b4, Te6edf3modeTb4b4b4.Te6edf3overlayTb4b4b4.Te6edf3relatedNodeNumsTb4b4b4.Te6edf3sizeTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Tff7b72val Te6edf3tracerouteForwardPointsTb4b4b4: Te6edf3ListTff7b72<Te6edf3LatLngTff7b72> Tff7b72=
Tff7b72if Tb4b4b4(Te6edf3mode Tff7b72is Te6edf3GoogleMapModeTb4b4b4.Te6edf3Traceroute Tff7b72&Tff7b72& Te6edf3tracerouteSelection Tff7b72!Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3nodeLookup Tff7b72= Te6edf3tracerouteSelectionTb4b4b4.Te6edf3nodeLookup
Te6edf3rememberTb4b4b4(Te6edf3modeTb4b4b4.Te6edf3overlayTb4b4b4, Te6edf3nodeLookupTb4b4b4) Tb4b4b4{
Te6edf3modeTb4b4b4.Te6edf3overlayTff7b72?.Te6edf3forwardRouteTff7b72?.Te6edf3mapNotNull Tb4b4b4{ Te6edf3nodeLookupTff7b72[Tffa657itTff7b72]Tff7b72?.Te6edf3positionTff7b72?.Te6edf3toLatLngTb4b4b4(Tb4b4b4) Tb4b4b4} Tff7b72?: Te6edf3emptyListTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3emptyListTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tff7b72val Te6edf3tracerouteReturnPointsTb4b4b4: Te6edf3ListTff7b72<Te6edf3LatLngTff7b72> Tff7b72=
Tff7b72if Tb4b4b4(Te6edf3mode Tff7b72is Te6edf3GoogleMapModeTb4b4b4.Te6edf3Traceroute Tff7b72&Tff7b72& Te6edf3tracerouteSelection Tff7b72!Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3nodeLookup Tff7b72= Te6edf3tracerouteSelectionTb4b4b4.Te6edf3nodeLookup
Te6edf3rememberTb4b4b4(Te6edf3modeTb4b4b4.Te6edf3overlayTb4b4b4, Te6edf3nodeLookupTb4b4b4) Tb4b4b4{
Te6edf3modeTb4b4b4.Te6edf3overlayTff7b72?.Te6edf3returnRouteTff7b72?.Te6edf3mapNotNull Tb4b4b4{ Te6edf3nodeLookupTff7b72[Tffa657itTff7b72]Tff7b72?.Te6edf3positionTff7b72?.Te6edf3toLatLngTb4b4b4(Tb4b4b4) Tb4b4b4} Tff7b72?: Te6edf3emptyListTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3emptyListTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tff7b72val Te6edf3tracerouteHeadingReferencePoints Tff7b72=
Te6edf3rememberTb4b4b4(Te6edf3tracerouteForwardPointsTb4b4b4, Te6edf3tracerouteReturnPointsTb4b4b4) Tb4b4b4{
Tff7b72when Tb4b4b4{
Te6edf3tracerouteForwardPointsTb4b4b4.Te6edf3size Tff7b72>Tff7b72= T79c0ff2 Tff7b72-Tff7b72> Te6edf3tracerouteForwardPoints
Te6edf3tracerouteReturnPointsTb4b4b4.Te6edf3size Tff7b72>Tff7b72= T79c0ff2 Tff7b72-Tff7b72> Te6edf3tracerouteReturnPoints
Tff7b72else Tff7b72-Tff7b72> Te6edf3emptyListTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tff7b72val Te6edf3tracerouteForwardOffsetPoints Tff7b72=
Te6edf3rememberTb4b4b4(Te6edf3tracerouteForwardPointsTb4b4b4, Te6edf3tracerouteHeadingReferencePointsTb4b4b4) Tb4b4b4{
Te6edf3offsetPolylineTb4b4b4(Te6edf3tracerouteForwardPointsTb4b4b4, Te6edf3TRACEROUTE_OFFSET_METERSTb4b4b4, Te6edf3tracerouteHeadingReferencePointsTb4b4b4, T79c0ff1.0Tb4b4b4)
Tb4b4b4}
Tff7b72val Te6edf3tracerouteReturnOffsetPoints Tff7b72=
Te6edf3rememberTb4b4b4(Te6edf3tracerouteReturnPointsTb4b4b4, Te6edf3tracerouteHeadingReferencePointsTb4b4b4) Tb4b4b4{
Te6edf3offsetPolylineTb4b4b4(Te6edf3tracerouteReturnPointsTb4b4b4, Te6edf3TRACEROUTE_OFFSET_METERSTb4b4b4, Te6edf3tracerouteHeadingReferencePointsTb4b4b4, Tff7b72-T79c0ff1.0Tb4b4b4)
Tb4b4b4}

T8b949e// Auto-centering for NodeTrack / Traceroute modes
Tff7b72var Te6edf3hasCentered Tff7b72by Te6edf3rememberTb4b4b4(Te6edf3modeTb4b4b4) Tb4b4b4{ Te6edf3mutableStateOfTb4b4b4(Tff7b72falseTb4b4b4) Tb4b4b4}

Tff7b72if Tb4b4b4(Te6edf3mode Tff7b72is Te6edf3GoogleMapModeTb4b4b4.Te6edf3NodeTrackTb4b4b4) Tb4b4b4{
Te6edf3LaunchedEffectTb4b4b4(Te6edf3sortedTrackPositionsTb4b4b4, Te6edf3hasCenteredTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3hasCentered Tff7b72|Tff7b72| Te6edf3sortedTrackPositionsTb4b4b4.Te6edf3isEmptyTb4b4b4(Tb4b4b4)Tb4b4b4) Tff7b72returnTf0883e@LaunchedEffect
Tff7b72val Te6edf3points Tff7b72= Te6edf3sortedTrackPositionsTb4b4b4.Te6edf3map Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3toLatLngTb4b4b4(Tb4b4b4) Tb4b4b4}
Tff7b72val Te6edf3cameraUpdate Tff7b72=
Tff7b72if Tb4b4b4(Te6edf3pointsTb4b4b4.Te6edf3size Tff7b72=Tff7b72= T79c0ff1Tb4b4b4) Tb4b4b4{
Te6edf3CameraUpdateFactoryTb4b4b4.Te6edf3newLatLngZoomTb4b4b4(Te6edf3pointsTb4b4b4.Te6edf3firstTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3maxTb4b4b4(Te6edf3cameraPositionStateTb4b4b4.Te6edf3positionTb4b4b4.Te6edf3zoomTb4b4b4, T79c0ff1T79c0ff2fTb4b4b4)Tb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72val Te6edf3bounds Tff7b72= Te6edf3LatLngBoundsTb4b4b4.Te6edf3builderTb4b4b4(Tb4b4b4)
Te6edf3pointsTb4b4b4.Te6edf3forEach Tb4b4b4{ Te6edf3boundsTb4b4b4.Te6edf3includeTb4b4b4(Tffa657itTb4b4b4) Tb4b4b4}
Te6edf3CameraUpdateFactoryTb4b4b4.Te6edf3newLatLngBoundsTb4b4b4(Te6edf3boundsTb4b4b4.Te6edf3buildTb4b4b4(Tb4b4b4)Tb4b4b4, T79c0ff8T79c0ff0Tb4b4b4)
Tb4b4b4}
Tff7b72try Tb4b4b4{
Te6edf3cameraPositionStateTb4b4b4.Te6edf3animateTb4b4b4(Te6edf3cameraUpdateTb4b4b4)
Te6edf3hasCentered Tff7b72= Tff7b72true
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3IllegalStateExceptionTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3d Tb4b4b4{ Ta5d6ff"Ta5d6ffError centering track map: Tffd700${Te6edf3eTb4b4b4.Te6edf3messageTffd700}Ta5d6ff" Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

T8b949e// Animate to selected position marker when card is tapped in the list
Te6edf3LaunchedEffectTb4b4b4(Te6edf3modeTb4b4b4.Te6edf3selectedPositionTimeTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3selectedTime Tff7b72= Te6edf3modeTb4b4b4.Te6edf3selectedPositionTime Tff7b72?: Tff7b72returnTf0883e@LaunchedEffect
Tff7b72val Te6edf3selectedPos Tff7b72= Te6edf3sortedTrackPositionsTb4b4b4.Te6edf3find Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3time Tff7b72=Tff7b72= Te6edf3selectedTime Tb4b4b4} Tff7b72?: Tff7b72returnTf0883e@LaunchedEffect
Tff7b72try Tb4b4b4{
Te6edf3cameraPositionStateTb4b4b4.Te6edf3animateTb4b4b4(Te6edf3CameraUpdateFactoryTb4b4b4.Te6edf3newLatLngTb4b4b4(Te6edf3selectedPosTb4b4b4.Te6edf3toLatLngTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4)
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3IllegalStateExceptionTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3d Tb4b4b4{ Ta5d6ff"Ta5d6ffError animating to selected position: Tffd700${Te6edf3eTb4b4b4.Te6edf3messageTffd700}Ta5d6ff" Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Tff7b72if Tb4b4b4(Te6edf3mode Tff7b72is Te6edf3GoogleMapModeTb4b4b4.Te6edf3TracerouteTb4b4b4) Tb4b4b4{
Te6edf3LaunchedEffectTb4b4b4(Te6edf3modeTb4b4b4.Te6edf3overlayTb4b4b4, Te6edf3tracerouteForwardPointsTb4b4b4, Te6edf3tracerouteReturnPointsTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3modeTb4b4b4.Te6edf3overlay Tff7b72=Tff7b72= Tff7b72null Tff7b72|Tff7b72| Te6edf3hasCenteredTb4b4b4) Tff7b72returnTf0883e@LaunchedEffect
Tff7b72val Te6edf3allPoints Tff7b72= Tb4b4b4(Te6edf3tracerouteForwardPoints Tff7b72+ Te6edf3tracerouteReturnPointsTb4b4b4)Tb4b4b4.Te6edf3distinctTb4b4b4(Tb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3allPointsTb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3cameraUpdate Tff7b72=
Tff7b72if Tb4b4b4(Te6edf3allPointsTb4b4b4.Te6edf3size Tff7b72=Tff7b72= T79c0ff1Tb4b4b4) Tb4b4b4{
Te6edf3CameraUpdateFactoryTb4b4b4.Te6edf3newLatLngZoomTb4b4b4(
Te6edf3allPointsTb4b4b4.Te6edf3firstTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3maxTb4b4b4(Te6edf3cameraPositionStateTb4b4b4.Te6edf3positionTb4b4b4.Te6edf3zoomTb4b4b4, T79c0ff1T79c0ff2fTb4b4b4)Tb4b4b4,
Tb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72val Te6edf3bounds Tff7b72= Te6edf3LatLngBoundsTb4b4b4.Te6edf3builderTb4b4b4(Tb4b4b4)
Te6edf3allPointsTb4b4b4.Te6edf3forEach Tb4b4b4{ Te6edf3boundsTb4b4b4.Te6edf3includeTb4b4b4(Tffa657itTb4b4b4) Tb4b4b4}
Te6edf3CameraUpdateFactoryTb4b4b4.Te6edf3newLatLngBoundsTb4b4b4(Te6edf3boundsTb4b4b4.Te6edf3buildTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3TRACEROUTE_BOUNDS_PADDING_PXTb4b4b4)
Tb4b4b4}
Tff7b72try Tb4b4b4{
Te6edf3cameraPositionStateTb4b4b4.Te6edf3animateTb4b4b4(Te6edf3cameraUpdateTb4b4b4)
Te6edf3hasCentered Tff7b72= Tff7b72true
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3IllegalStateExceptionTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3d Tb4b4b4{ Ta5d6ff"Ta5d6ffError centering traceroute overlay: Tffd700${Te6edf3eTb4b4b4.Te6edf3messageTffd700}Ta5d6ff" Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

T8b949e// --- Tile & layers state ---
Tff7b72var Te6edf3showLayersBottomSheet Tff7b72by Te6edf3remember Tb4b4b4{ Te6edf3mutableStateOfTb4b4b4(Tff7b72falseTb4b4b4) Tb4b4b4}
T8b949e// Non-null while the Site Planner estimate dialog/runner is open, retaining its node-location source.
Tff7b72var Te6edf3sitePlannerLaunch Tff7b72by Te6edf3remember Tb4b4b4{ Te6edf3mutableStateOfTff7b72<Te6edf3SitePlannerLaunch?Tff7b72>Tb4b4b4(Tff7b72nullTb4b4b4) Tb4b4b4}

Tff7b72val Te6edf3onAddLayerClicked Tff7b72= Tb4b4b4{
Tff7b72val Te6edf3intent Tff7b72=
Te6edf3IntentTb4b4b4(Te6edf3IntentTb4b4b4.Te6edf3ACTION_OPEN_DOCUMENTTb4b4b4)Tb4b4b4.Te6edf3apply Tb4b4b4{
Te6edf3addCategoryTb4b4b4(Te6edf3IntentTb4b4b4.Te6edf3CATEGORY_OPENABLETb4b4b4)
T8b949e// Providers may assign generic MIME types to valid map files; validate the extension after selection.
Te6edf3type Tff7b72= Ta5d6ff"Ta5d6ff*/*Ta5d6ff"
Tb4b4b4}
Te6edf3filePickerLauncherTb4b4b4.Te6edf3launchTb4b4b4(Te6edf3intentTb4b4b4)
Tb4b4b4}
Tff7b72val Te6edf3onRemoveLayer Tff7b72= Tb4b4b4{ Te6edf3layerIdTb4b4b4: Tffa657String Tff7b72-Tff7b72> Te6edf3mapViewModelTb4b4b4.Te6edf3removeMapLayerTb4b4b4(Te6edf3layerIdTb4b4b4) Tb4b4b4}
Tff7b72val Te6edf3onToggleVisibility Tff7b72= Tb4b4b4{ Te6edf3layerIdTb4b4b4: Tffa657String Tff7b72-Tff7b72> Te6edf3mapViewModelTb4b4b4.Te6edf3toggleLayerVisibilityTb4b4b4(Te6edf3layerIdTb4b4b4) Tb4b4b4}

Tff7b72val Te6edf3effectiveGoogleMapType Tff7b72= Tff7b72if Tb4b4b4(Te6edf3currentRasterBasemap Tff7b72!Tff7b72= Tff7b72nullTb4b4b4) Te6edf3MapTypeTb4b4b4.Te6edf3NONE Tff7b72else Te6edf3selectedGoogleMapType

Tff7b72var Te6edf3showClusterItemsDialog Tff7b72by Te6edf3remember Tb4b4b4{ Te6edf3mutableStateOfTff7b72<Te6edf3ListTff7b72<Te6edf3NodeClusterItemTff7b72>Tff7b72?Tff7b72>Tb4b4b4(Tff7b72nullTb4b4b4) Tb4b4b4}

Te6edf3KeepScreenOnTb4b4b4(Te6edf3isLocationTrackingEnabled Tff7b72&Tff7b72& Te6edf3locationPermissionTb4b4b4.Te6edf3isGrantedTb4b4b4)

T8b949e// --- Main UI ---
Tff7b72val Te6edf3isMainMode Tff7b72= Te6edf3mode Tff7b72is Te6edf3GoogleMapModeTb4b4b4.Te6edf3Main

Te6edf3BoxTb4b4b4(Te6edf3modifier Tff7b72= Te6edf3modifierTb4b4b4) Tb4b4b4{
Te6edf3GoogleMapTb4b4b4(
Te6edf3mapColorScheme Tff7b72= Te6edf3mapColorSchemeTb4b4b4,
Te6edf3modifier Tff7b72= Te6edf3ModifierTb4b4b4.Te6edf3fillMaxSizeTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3cameraPositionState Tff7b72= Te6edf3cameraPositionStateTb4b4b4,
Te6edf3uiSettings Tff7b72=
Te6edf3MapUiSettingsTb4b4b4(
Te6edf3zoomControlsEnabled Tff7b72= Tff7b72trueTb4b4b4,
Te6edf3mapToolbarEnabled Tff7b72= Te6edf3isMainModeTb4b4b4,
Te6edf3compassEnabled Tff7b72= Tff7b72falseTb4b4b4,
Te6edf3myLocationButtonEnabled Tff7b72= Tff7b72falseTb4b4b4,
Te6edf3rotationGesturesEnabled Tff7b72= Tff7b72trueTb4b4b4,
Te6edf3scrollGesturesEnabled Tff7b72= Tff7b72trueTb4b4b4,
Te6edf3tiltGesturesEnabled Tff7b72= Te6edf3isMainModeTb4b4b4,
Te6edf3zoomGesturesEnabled Tff7b72= Tff7b72trueTb4b4b4,
Tb4b4b4)Tb4b4b4,
Te6edf3properties Tff7b72=
Te6edf3MapPropertiesTb4b4b4(
Te6edf3mapType Tff7b72= Te6edf3effectiveGoogleMapTypeTb4b4b4,
Te6edf3isMyLocationEnabled Tff7b72= Te6edf3isLocationTrackingEnabled Tff7b72&Tff7b72& Te6edf3locationPermissionTb4b4b4.Te6edf3isGrantedTb4b4b4,
Tb4b4b4)Tb4b4b4,
Te6edf3onMapLoaded Tff7b72= Tb4b4b4{ Te6edf3isMapLoaded Tff7b72= Tff7b72true Tb4b4b4}Tb4b4b4,
Te6edf3onMapClick Tff7b72= Tb4b4b4{ Te6edf3latLng Tff7b72-Tff7b72>
Tff7b72if Tb4b4b4(Te6edf3isMainMode Tff7b72&Tff7b72& Te6edf3boxAuthoringDraft Tff7b72!Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3first Tff7b72= Te6edf3boxAuthoringFirstCorner
Tff7b72if Tb4b4b4(Te6edf3first Tff7b72=Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Te6edf3boxAuthoringFirstCorner Tff7b72= Te6edf3latLng
Tb4b4b4} Tff7b72else Tff7b72if Tb4b4b4(
Te6edf3absTb4b4b4(Te6edf3latLngTb4b4b4.Te6edf3latitude Tff7b72- Te6edf3firstTb4b4b4.Te6edf3latitudeTb4b4b4) Tff7b72>Tff7b72= Te6edf3BOX_AUTHORING_MIN_CORNER_DELTA Tff7b72&Tff7b72&
Te6edf3absTb4b4b4(Te6edf3latLngTb4b4b4.Te6edf3longitude Tff7b72- Te6edf3firstTb4b4b4.Te6edf3longitudeTb4b4b4) Tff7b72>Tff7b72= Te6edf3BOX_AUTHORING_MIN_CORNER_DELTA
Tb4b4b4) Tb4b4b4{
T8b949e// Only commit when the two corners are meaningfully distinct; a near-identical second tap
T8b949e// would yield a zero-area box, so ignore it and keep waiting for a valid second corner.
Te6edf3boxAuthoringSecondCorner Tff7b72= Te6edf3latLng
Tff7b72val Te6edf3box Tff7b72= Te6edf3boundingBoxFromCornersTb4b4b4(Te6edf3firstTb4b4b4, Te6edf3latLngTb4b4b4)
Te6edf3editingWaypoint Tff7b72= Te6edf3boxAuthoringDraftTff7b72?.Te6edf3copyTb4b4b4(Te6edf3bounding_box Tff7b72= Te6edf3boxTb4b4b4)
Te6edf3boxAuthoringDraft Tff7b72= Tff7b72null
Te6edf3boxAuthoringFirstCorner Tff7b72= Tff7b72null
Te6edf3boxAuthoringSecondCorner Tff7b72= Tff7b72null
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}Tb4b4b4,
Te6edf3onMapLongClick Tff7b72= Tb4b4b4{ Te6edf3latLng Tff7b72-Tff7b72>
Tff7b72if Tb4b4b4(Te6edf3isMainMode Tff7b72&Tff7b72& Te6edf3isConnected Tff7b72&Tff7b72& Te6edf3boxAuthoringDraft Tff7b72=Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Te6edf3editingWaypoint Tff7b72=
Te6edf3WaypointTb4b4b4(
Te6edf3latitude_i Tff7b72= Tb4b4b4(Te6edf3latLngTb4b4b4.Te6edf3latitude Tff7b72/ Te6edf3DEG_DTb4b4b4)Tb4b4b4.Te6edf3toIntTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3longitude_i Tff7b72= Tb4b4b4(Te6edf3latLngTb4b4b4.Te6edf3longitude Tff7b72/ Te6edf3DEG_DTb4b4b4)Tb4b4b4.Te6edf3toIntTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}Tb4b4b4,
Tb4b4b4) Tb4b4b4{
T8b949e// The raster basemap, when one is selected instead of a Google map type (all modes).
Te6edf3keyTb4b4b4(Te6edf3currentRasterBasemapTb4b4b4) Tb4b4b4{
Te6edf3currentRasterBasemapTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3basemap Tff7b72-Tff7b72>
Te6edf3mapViewModelTb4b4b4.Te6edf3getTileProviderTb4b4b4(Te6edf3basemapTb4b4b4)Tff7b72?.Te6edf3let Tb4b4b4{ Te6edf3tileProvider Tff7b72-Tff7b72>
Te6edf3TileOverlayTb4b4b4(Te6edf3tileProvider Tff7b72= Te6edf3tileProviderTb4b4b4, Te6edf3fadeIn Tff7b72= Tff7b72trueTb4b4b4, Te6edf3transparency Tff7b72= T79c0ff0fTb4b4b4, Te6edf3zIndex Tff7b72= Tff7b72-T79c0ff1fTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

T8b949e// The downloaded region (if any) covering what's on screen — shared by the offline vector overlay and
T8b949e// offline terrain below, each gated by its own toggle rather than each other's.
Tff7b72val Te6edf3visibleBounds Tff7b72= Te6edf3cameraPositionStateTb4b4b4.Te6edf3projectionTff7b72?.Te6edf3visibleRegionTff7b72?.Te6edf3latLngBounds
Tff7b72val Te6edf3coveringRegion Tff7b72= Te6edf3visibleBoundsTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3mapViewModelTb4b4b4.Te6edf3offlineRegionCoveringTb4b4b4(Tffa657itTb4b4b4) Tb4b4b4}

T8b949e// The offline vector overlay, drawn only while the user has switched it on and a downloaded region
T8b949e// actually covers what's on screen — see MapViewModel.offlineOverlayEnabled/offlineRegionCovering.
Tff7b72if Tb4b4b4(Te6edf3offlineOverlayEnabledTb4b4b4) Tb4b4b4{
Te6edf3coveringRegionTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3region Tff7b72-Tff7b72>
Te6edf3OfflineVectorOverlayTb4b4b4(
Te6edf3region Tff7b72= Te6edf3regionTb4b4b4,
Te6edf3archiveFile Tff7b72= Te6edf3mapViewModelTb4b4b4.Te6edf3offlineRegionArchiveFileTb4b4b4(Te6edf3regionTb4b4b4.Te6edf3idTb4b4b4)Tb4b4b4,
Te6edf3cameraPositionState Tff7b72= Te6edf3cameraPositionStateTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}

T8b949e// Offline terrain (hillshade + contours) — independent of the vector overlay's own toggle, gated only
T8b949e// by its own two switches and whether the covering region actually has terrain downloaded. See
T8b949e// MapViewModel.terrainHillshadeEnabled/terrainContoursEnabled and OfflineRegionManagerSection.
Tff7b72if Tb4b4b4(Te6edf3coveringRegionTff7b72?.Te6edf3hasTerrain Tff7b72=Tff7b72= Tff7b72trueTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3terrainHillshadeEnabledTb4b4b4) Tb4b4b4{
Te6edf3keyTb4b4b4(Te6edf3coveringRegionTb4b4b4.Te6edf3idTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3hillshadeProvider Tff7b72=
Te6edf3rememberTb4b4b4(Te6edf3coveringRegionTb4b4b4.Te6edf3idTb4b4b4) Tb4b4b4{
Te6edf3HillshadeTileProviderTb4b4b4(Te6edf3mapViewModelTb4b4b4.Te6edf3terrainStoreForRegionTb4b4b4(Te6edf3coveringRegionTb4b4b4.Te6edf3idTb4b4b4)Tb4b4b4)
Tb4b4b4}
Te6edf3TileOverlayTb4b4b4(
Te6edf3tileProvider Tff7b72= Te6edf3hillshadeProviderTb4b4b4,
Te6edf3fadeIn Tff7b72= Tff7b72trueTb4b4b4,
Te6edf3transparency Tff7b72= T79c0ff0fTb4b4b4,
Te6edf3zIndex Tff7b72= Te6edf3TERRAIN_HILLSHADE_Z_INDEXTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3terrainContoursEnabledTb4b4b4) Tb4b4b4{
Te6edf3ContourOverlayTb4b4b4(
Te6edf3region Tff7b72= Te6edf3coveringRegionTb4b4b4,
Te6edf3store Tff7b72= Te6edf3mapViewModelTb4b4b4.Te6edf3terrainStoreForRegionTb4b4b4(Te6edf3coveringRegionTb4b4b4.Te6edf3idTb4b4b4)Tb4b4b4,
Te6edf3cameraPositionState Tff7b72= Te6edf3cameraPositionStateTb4b4b4,
Te6edf3metric Tff7b72= Te6edf3displayUnits Tff7b72=Tff7b72= Te6edf3MeasurementSystemTb4b4b4.Te6edf3METRICTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}

T8b949e// Overlays composite over whichever basemap is in use, and stay below the mesh drawn above them.
Te6edf3mapViewModelTb4b4b4.Te6edf3availableOverlays
Tb4b4b4.Te6edf3filter Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3id Tff7b72in Te6edf3enabledOverlayIds Tb4b4b4}
Tb4b4b4.Te6edf3forEach Tb4b4b4{ Te6edf3overlay Tff7b72-Tff7b72>
Te6edf3keyTb4b4b4(Te6edf3overlayTb4b4b4.Te6edf3idTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3provider Tff7b72= Te6edf3rememberTb4b4b4(Te6edf3overlayTb4b4b4.Te6edf3idTb4b4b4) Tb4b4b4{ Te6edf3mapViewModelTb4b4b4.Te6edf3createTileProviderTb4b4b4(Te6edf3overlayTb4b4b4.Te6edf3specTb4b4b4) Tb4b4b4}
Te6edf3TileOverlayTb4b4b4(
Te6edf3tileProvider Tff7b72= Te6edf3providerTb4b4b4,
Te6edf3fadeIn Tff7b72= Tff7b72trueTb4b4b4,
Te6edf3transparency Tff7b72= T79c0ff1f Tff7b72- Te6edf3layerOpacityTb4b4b4.Te6edf3opacityOfTb4b4b4(Te6edf3overlayTb4b4b4.Te6edf3idTb4b4b4)Tb4b4b4,
Te6edf3zIndex Tff7b72= Te6edf3OVERLAY_Z_INDEXTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}

T8b949e// The two-tap flow commits on the second tap, so there is no both-corners-uncommitted state to draw a
T8b949e// rectangle preview from; instead mark the first tapped corner so the user sees it registered.
Te6edf3boxAuthoringFirstCornerTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3first Tff7b72-Tff7b72>
Tff7b72val Te6edf3cornerState Tff7b72= Te6edf3rememberUpdatedMarkerStateTb4b4b4(Te6edf3position Tff7b72= Te6edf3firstTb4b4b4)
Te6edf3MarkerComposableTb4b4b4(Te6edf3state Tff7b72= Te6edf3cornerStateTb4b4b4, Te6edf3zIndex Tff7b72= T79c0ff5fTb4b4b4) Tb4b4b4{
Te6edf3BoxTb4b4b4(
Te6edf3modifier Tff7b72=
Te6edf3ModifierTb4b4b4.Te6edf3sizeTb4b4b4(T79c0ff1T79c0ff6.Te6edf3dpTb4b4b4)
Tb4b4b4.Te6edf3backgroundTb4b4b4(Te6edf3GEOFENCE_OVERLAY_COLORTb4b4b4, Te6edf3CircleShapeTb4b4b4)
Tb4b4b4.Te6edf3borderTb4b4b4(T79c0ff2.Te6edf3dpTb4b4b4, Te6edf3ColorTb4b4b4.Te6edf3WhiteTb4b4b4, Te6edf3CircleShapeTb4b4b4)Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}

Tff7b72when Tb4b4b4(Te6edf3modeTb4b4b4) Tb4b4b4{
Tff7b72is Te6edf3GoogleMapModeTb4b4b4.Te6edf3Main Tff7b72-Tff7b72>
Te6edf3MainMapContentTb4b4b4(
Te6edf3nodeClusterItems Tff7b72= Te6edf3nodeClusterItemsTb4b4b4,
Te6edf3mapFilterState Tff7b72= Te6edf3mapFilterStateTb4b4b4,
Te6edf3navigateToNodeDetails Tff7b72= Te6edf3navigateToNodeDetailsTb4b4b4,
Te6edf3displayableWaypoints Tff7b72= Te6edf3displayableWaypointsTb4b4b4,
Te6edf3myNodeNum Tff7b72= Te6edf3myNodeNumTb4b4b4,
Te6edf3onEditWaypointRequest Tff7b72= Tb4b4b4{ Te6edf3editingWaypoint Tff7b72= Tffa657it Tb4b4b4}Tb4b4b4,
Te6edf3onDeleteWaypointRequest Tff7b72= Tb4b4b4{ Te6edf3deletingWaypoint Tff7b72= Tffa657it Tb4b4b4}Tb4b4b4,
Te6edf3onShowGeofenceInfo Tff7b72= Tb4b4b4{ Te6edf3geofenceInfoWaypoint Tff7b72= Tffa657it Tb4b4b4}Tb4b4b4,
Te6edf3selectedWaypointId Tff7b72= Te6edf3selectedWaypointIdTb4b4b4,
Te6edf3mapLayers Tff7b72= Te6edf3mapLayersTb4b4b4,
Te6edf3layerOpacity Tff7b72= Te6edf3layerOpacityTb4b4b4,
Te6edf3mapViewModel Tff7b72= Te6edf3mapViewModelTb4b4b4,
Te6edf3cameraPositionState Tff7b72= Te6edf3cameraPositionStateTb4b4b4,
Te6edf3coroutineScope Tff7b72= Te6edf3coroutineScopeTb4b4b4,
Te6edf3onShowClusterItemsDialog Tff7b72= Tb4b4b4{ Te6edf3showClusterItemsDialog Tff7b72= Tffa657it Tb4b4b4}Tb4b4b4,
Tb4b4b4)

Tff7b72is Te6edf3GoogleMapModeTb4b4b4.Te6edf3NodeTrack Tff7b72-Tff7b72> Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3modeTb4b4b4.Te6edf3focusedNode Tff7b72!Tff7b72= Tff7b72null Tff7b72&Tff7b72& Te6edf3sortedTrackPositionsTb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3NodeTrackOverlayTb4b4b4(
Te6edf3focusedNode Tff7b72= Te6edf3modeTb4b4b4.Te6edf3focusedNodeTb4b4b4,
Te6edf3sortedPositions Tff7b72= Te6edf3sortedTrackPositionsTb4b4b4,
Te6edf3displayUnits Tff7b72= Te6edf3displayUnitsTb4b4b4,
Te6edf3myNodeNum Tff7b72= Te6edf3myNodeNumTb4b4b4,
Te6edf3selectedPositionTime Tff7b72= Te6edf3modeTb4b4b4.Te6edf3selectedPositionTimeTb4b4b4,
Te6edf3onPositionSelect Tff7b72= Te6edf3modeTb4b4b4.Te6edf3onPositionSelectedTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}

Tff7b72is Te6edf3GoogleMapModeTb4b4b4.Te6edf3Traceroute Tff7b72-Tff7b72>
Te6edf3TracerouteMapContentTb4b4b4(
Te6edf3forwardOffsetPoints Tff7b72= Te6edf3tracerouteForwardOffsetPointsTb4b4b4,
Te6edf3returnOffsetPoints Tff7b72= Te6edf3tracerouteReturnOffsetPointsTb4b4b4,
Te6edf3forwardPointCount Tff7b72= Te6edf3tracerouteForwardPointsTb4b4b4.Te6edf3sizeTb4b4b4,
Te6edf3returnPointCount Tff7b72= Te6edf3tracerouteReturnPointsTb4b4b4.Te6edf3sizeTb4b4b4,
Te6edf3displayNodes Tff7b72= Te6edf3tracerouteDisplayNodesTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}

Te6edf3OfflineStatusBannerTb4b4b4(
Te6edf3visible Tff7b72= Tff7b72!Te6edf3mapNetworkAvailableTb4b4b4,
Te6edf3modifier Tff7b72= Te6edf3ModifierTb4b4b4.Te6edf3alignTb4b4b4(Te6edf3AlignmentTb4b4b4.Te6edf3TopStartTb4b4b4)Tb4b4b4.Te6edf3paddingTb4b4b4(Te6edf3top Tff7b72= T79c0ff8.Te6edf3dpTb4b4b4, Te6edf3start Tff7b72= T79c0ff8.Te6edf3dpTb4b4b4)Tb4b4b4,
Tb4b4b4)

T8b949e// Scale bar
Te6edf3ScaleBarTb4b4b4(
Te6edf3cameraPositionState Tff7b72= Te6edf3cameraPositionStateTb4b4b4,
Te6edf3modifier Tff7b72= Te6edf3ModifierTb4b4b4.Te6edf3alignTb4b4b4(Te6edf3AlignmentTb4b4b4.Te6edf3BottomStartTb4b4b4)Tb4b4b4.Te6edf3paddingTb4b4b4(Te6edf3bottom Tff7b72= Tff7b72if Tb4b4b4(Te6edf3isMainModeTb4b4b4) T79c0ff4T79c0ff8.Te6edf3dp Tff7b72else T79c0ff1T79c0ff6.Te6edf3dpTb4b4b4)Tb4b4b4,
Tb4b4b4)

T8b949e// Waypoint edit dialog (Main mode only)
Tff7b72if Tb4b4b4(Te6edf3isMainModeTb4b4b4) Tb4b4b4{
Te6edf3editingWaypointTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3waypointToEdit Tff7b72-Tff7b72>
Te6edf3EditWaypointDialogTb4b4b4(
Te6edf3waypoint Tff7b72= Te6edf3waypointToEditTb4b4b4,
Te6edf3displayUnits Tff7b72= Te6edf3displayUnitsTb4b4b4,
Te6edf3myNodeNum Tff7b72= Te6edf3myNodeNumTb4b4b4,
Te6edf3onSend Tff7b72= Tb4b4b4{ Te6edf3updatedWp Tff7b72-Tff7b72>
Tff7b72var Te6edf3finalWp Tff7b72= Te6edf3updatedWp
Tff7b72if Tb4b4b4(Te6edf3updatedWpTb4b4b4.Te6edf3id Tff7b72=Tff7b72= T79c0ff0Tb4b4b4) Tb4b4b4{
Te6edf3finalWp Tff7b72= Te6edf3finalWpTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3id Tff7b72= Te6edf3mapViewModelTb4b4b4.Te6edf3generatePacketIdTb4b4b4(Tb4b4b4)Tb4b4b4)
Tb4b4b4}
Te6edf3finalWp Tff7b72= Te6edf3finalWpTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3icon Tff7b72= Te6edf3finalWpTb4b4b4.Te6edf3iconTb4b4b4.Te6edf3waypointIconOrDefaultTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3mapViewModelTb4b4b4.Te6edf3sendWaypointTb4b4b4(Te6edf3finalWpTb4b4b4)
Te6edf3editingWaypoint Tff7b72= Tff7b72null
Tb4b4b4}Tb4b4b4,
Te6edf3onDelete Tff7b72= Tb4b4b4{ Te6edf3wpToDelete Tff7b72-Tff7b72>
T8b949e// Broadcast the removal (expire=1) only for waypoints we're allowed to modify mesh-wide
T8b949e// (unlocked, or locked to us); otherwise just drop our local copy below.
Tff7b72if Tb4b4b4(Te6edf3wpToDeleteTb4b4b4.Te6edf3isModifiableByTb4b4b4(Te6edf3myNodeNumTb4b4b4) Tff7b72&Tff7b72& Te6edf3isConnected Tff7b72&Tff7b72& Te6edf3wpToDeleteTb4b4b4.Te6edf3id Tff7b72!Tff7b72= T79c0ff0Tb4b4b4) Tb4b4b4{
Te6edf3mapViewModelTb4b4b4.Te6edf3sendWaypointTb4b4b4(Te6edf3wpToDeleteTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3expire Tff7b72= T79c0ff1Tb4b4b4)Tb4b4b4)
Tb4b4b4}
Te6edf3mapViewModelTb4b4b4.Te6edf3deleteWaypointTb4b4b4(Te6edf3wpToDeleteTb4b4b4.Te6edf3idTb4b4b4)
Te6edf3editingWaypoint Tff7b72= Tff7b72null
Tb4b4b4}Tb4b4b4,
Te6edf3onDismissRequest Tff7b72= Tb4b4b4{ Te6edf3editingWaypoint Tff7b72= Tff7b72null Tb4b4b4}Tb4b4b4,
Te6edf3onBeginBoxAuthoring Tff7b72= Tb4b4b4{ Te6edf3draft Tff7b72-Tff7b72>
Te6edf3boxAuthoringDraft Tff7b72= Te6edf3draft
Te6edf3boxAuthoringFirstCorner Tff7b72= Tff7b72null
Te6edf3boxAuthoringSecondCorner Tff7b72= Tff7b72null
Te6edf3editingWaypoint Tff7b72= Tff7b72null
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tb4b4b4}

Te6edf3deletingWaypointTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3waypoint Tff7b72-Tff7b72>
Te6edf3DeleteWaypointDialogTb4b4b4(
Te6edf3canDeleteForEveryone Tff7b72= Te6edf3waypointTb4b4b4.Te6edf3isModifiableByTb4b4b4(Te6edf3myNodeNumTb4b4b4) Tff7b72&Tff7b72& Te6edf3isConnected Tff7b72&Tff7b72& Te6edf3waypointTb4b4b4.Te6edf3id Tff7b72!Tff7b72= T79c0ff0Tb4b4b4,
Te6edf3onDeleteForMe Tff7b72= Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3d Tb4b4b4{ Ta5d6ff"Ta5d6ffUser deleted waypoint Tffd700${Te6edf3waypointTb4b4b4.Te6edf3idTffd700}Ta5d6ff for meTa5d6ff" Tb4b4b4}
Te6edf3mapViewModelTb4b4b4.Te6edf3deleteWaypointTb4b4b4(Te6edf3waypointTb4b4b4.Te6edf3idTb4b4b4)
Te6edf3deletingWaypoint Tff7b72= Tff7b72null
Tb4b4b4}Tb4b4b4,
Te6edf3onDeleteForEveryone Tff7b72= Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3d Tb4b4b4{ Ta5d6ff"Ta5d6ffUser deleted waypoint Tffd700${Te6edf3waypointTb4b4b4.Te6edf3idTffd700}Ta5d6ff for everyoneTa5d6ff" Tb4b4b4}
Te6edf3mapViewModelTb4b4b4.Te6edf3sendWaypointTb4b4b4(Te6edf3waypointTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3expire Tff7b72= T79c0ff1Tb4b4b4)Tb4b4b4)
Te6edf3mapViewModelTb4b4b4.Te6edf3deleteWaypointTb4b4b4(Te6edf3waypointTb4b4b4.Te6edf3idTb4b4b4)
Te6edf3deletingWaypoint Tff7b72= Tff7b72null
Tb4b4b4}Tb4b4b4,
Te6edf3onDismissRequest Tff7b72= Tb4b4b4{ Te6edf3deletingWaypoint Tff7b72= Tff7b72null Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tb4b4b4}

Te6edf3geofenceInfoWaypointTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3waypoint Tff7b72-Tff7b72>
Tff7b72val Te6edf3optIns Tff7b72by Te6edf3mapViewModelTb4b4b4.Te6edf3geofenceAlertOptInsTb4b4b4.Te6edf3collectAsStateWithLifecycleTb4b4b4(Tb4b4b4)
Te6edf3WaypointInfoDialogTb4b4b4(
Te6edf3waypoint Tff7b72= Te6edf3waypointTb4b4b4,
Te6edf3displayUnits Tff7b72= Te6edf3displayUnitsTb4b4b4,
Te6edf3alertsEnabled Tff7b72= Te6edf3waypointTb4b4b4.Te6edf3id Tff7b72in Te6edf3optInsTb4b4b4,
Te6edf3onToggleAlerts Tff7b72= Tb4b4b4{ Te6edf3mapViewModelTb4b4b4.Te6edf3setGeofenceAlertOptInTb4b4b4(Te6edf3waypointTb4b4b4.Te6edf3idTb4b4b4, Tffa657itTb4b4b4) Tb4b4b4}Tb4b4b4,
Te6edf3onDismissRequest Tff7b72= Tb4b4b4{ Te6edf3geofenceInfoWaypoint Tff7b72= Tff7b72null Tb4b4b4}Tb4b4b4,
T8b949e// Unlocked foreign geofences can still be edited/re-broadcast (only while connected, since editing
T8b949e// means re-sending); locked ones stay read-only.
Te6edf3onEdit Tff7b72=
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3waypointTb4b4b4.Te6edf3isLocked Tff7b72&Tff7b72& Te6edf3isConnectedTb4b4b4) Tb4b4b4{
Tb4b4b4{
Te6edf3geofenceInfoWaypoint Tff7b72= Tff7b72null
Te6edf3editingWaypoint Tff7b72= Te6edf3waypoint
Tb4b4b4}
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72null
Tb4b4b4}Tb4b4b4,
T8b949e// Dropping our local copy needs no mesh permission, so it's offered even when locked to its
T8b949e// creator.
Te6edf3onDeleteForMe Tff7b72= Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3d Tb4b4b4{ Ta5d6ff"Ta5d6ffUser deleted waypoint Tffd700${Te6edf3waypointTb4b4b4.Te6edf3idTffd700}Ta5d6ff for meTa5d6ff" Tb4b4b4}
Te6edf3mapViewModelTb4b4b4.Te6edf3deleteWaypointTb4b4b4(Te6edf3waypointTb4b4b4.Te6edf3idTb4b4b4)
Te6edf3geofenceInfoWaypoint Tff7b72= Tff7b72null
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}

T8b949e// Box-authoring affordance: instruct the user to tap two corners, with a cancel that re-opens the editor.
Te6edf3boxAuthoringDraftTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3draft Tff7b72-Tff7b72>
Te6edf3CardTb4b4b4(
Te6edf3modifier Tff7b72= Te6edf3ModifierTb4b4b4.Te6edf3alignTb4b4b4(Te6edf3AlignmentTb4b4b4.Te6edf3BottomCenterTb4b4b4)Tb4b4b4.Te6edf3paddingTb4b4b4(Te6edf3bottom Tff7b72= T79c0ff7T79c0ff2.Te6edf3dpTb4b4b4)Tb4b4b4.Te6edf3paddingTb4b4b4(Te6edf3horizontal Tff7b72= T79c0ff1T79c0ff6.Te6edf3dpTb4b4b4)Tb4b4b4,
Tb4b4b4) Tb4b4b4{
Te6edf3RowTb4b4b4(
Te6edf3modifier Tff7b72= Te6edf3ModifierTb4b4b4.Te6edf3paddingTb4b4b4(Te6edf3horizontal Tff7b72= T79c0ff1T79c0ff6.Te6edf3dpTb4b4b4, Te6edf3vertical Tff7b72= T79c0ff8.Te6edf3dpTb4b4b4)Tb4b4b4,
Te6edf3verticalAlignment Tff7b72= Te6edf3AlignmentTb4b4b4.Te6edf3CenterVerticallyTb4b4b4,
Tb4b4b4) Tb4b4b4{
Te6edf3TextTb4b4b4(
Te6edf3text Tff7b72= Te6edf3stringResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3geofence_box_author_hintTb4b4b4)Tb4b4b4,
Te6edf3modifier Tff7b72= Te6edf3ModifierTb4b4b4.Te6edf3weightTb4b4b4(T79c0ff1fTb4b4b4)Tb4b4b4,
Te6edf3style Tff7b72= Te6edf3MaterialThemeTb4b4b4.Te6edf3typographyTb4b4b4.Te6edf3bodyMediumTb4b4b4,
Tb4b4b4)
Te6edf3SpacerTb4b4b4(Te6edf3modifier Tff7b72= Te6edf3ModifierTb4b4b4.Te6edf3widthTb4b4b4(T79c0ff8.Te6edf3dpTb4b4b4)Tb4b4b4)
Te6edf3TextButtonTb4b4b4(
Te6edf3onClick Tff7b72= Tb4b4b4{
Te6edf3boxAuthoringDraft Tff7b72= Tff7b72null
Te6edf3boxAuthoringFirstCorner Tff7b72= Tff7b72null
Te6edf3boxAuthoringSecondCorner Tff7b72= Tff7b72null
Te6edf3editingWaypoint Tff7b72= Te6edf3draft
Tb4b4b4}Tb4b4b4,
Tb4b4b4) Tb4b4b4{
Te6edf3TextTb4b4b4(Te6edf3stringResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3cancelTb4b4b4)Tb4b4b4)
Tb4b4b4}
T8b949e// Single operable control: commits the currently-visible map bounds as the box, so the box can be
T8b949e// authored without the two precise corner taps (keyboard/screen-reader accessible path).
Te6edf3ButtonTb4b4b4(
Te6edf3onClick Tff7b72= Tb4b4b4{
Tff7b72val Te6edf3bounds Tff7b72= Te6edf3cameraPositionStateTb4b4b4.Te6edf3projectionTff7b72?.Te6edf3visibleRegionTff7b72?.Te6edf3latLngBounds
Tff7b72if Tb4b4b4(Te6edf3bounds Tff7b72!Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3box Tff7b72= Te6edf3boundingBoxFromCornersTb4b4b4(Te6edf3boundsTb4b4b4.Te6edf3southwestTb4b4b4, Te6edf3boundsTb4b4b4.Te6edf3northeastTb4b4b4)
Te6edf3editingWaypoint Tff7b72= Te6edf3boxAuthoringDraftTff7b72?.Te6edf3copyTb4b4b4(Te6edf3bounding_box Tff7b72= Te6edf3boxTb4b4b4)
Te6edf3boxAuthoringDraft Tff7b72= Tff7b72null
Te6edf3boxAuthoringFirstCorner Tff7b72= Tff7b72null
Te6edf3boxAuthoringSecondCorner Tff7b72= Tff7b72null
Tb4b4b4}
Tb4b4b4}Tb4b4b4,
Tb4b4b4) Tb4b4b4{
Te6edf3TextTb4b4b4(Te6edf3stringResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3geofence_box_use_viewTb4b4b4)Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

T8b949e// Controls overlay
Tff7b72val Te6edf3visibleNetworkLayers Tff7b72= Te6edf3mapLayersTb4b4b4.Te6edf3filter Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3isNetwork Tff7b72&Tff7b72& Tffa657itTb4b4b4.Te6edf3isVisible Tb4b4b4}
Tff7b72val Te6edf3showRefresh Tff7b72= Te6edf3visibleNetworkLayersTb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3isRefreshingLayers Tff7b72= Te6edf3visibleNetworkLayersTb4b4b4.Te6edf3any Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3isRefreshing Tb4b4b4}

T8b949e// Tile credit. OpenStreetMap's and Esri's tile policies both require it, and unlike MapLibre — which has an
T8b949e// attribution ornament of its own — the Google map has nowhere to put it but here.
T8b949e//
T8b949e// The offline vector layer's own credit is folded in here too, not left to the archive's metadata table
T8b949e// alone: an on-disk-only attribution is invisible to anyone who never opens the offline-region manager
T8b949e// sheet, which is exactly the gap this mirrors from the sibling iOS app's own terrain layer. The offline
T8b949e// terrain layer's own credit (Mapterhorn) is folded in the same way, whenever hillshade or contours are
T8b949e// actually rendering.
Tff7b72val Te6edf3attributionCoveringRegion Tff7b72=
Te6edf3cameraPositionStateTb4b4b4.Te6edf3projectionTff7b72?.Te6edf3visibleRegionTff7b72?.Te6edf3latLngBoundsTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3mapViewModelTb4b4b4.Te6edf3offlineRegionCoveringTb4b4b4(Tffa657itTb4b4b4) Tb4b4b4}
Tff7b72val Te6edf3offlineRegionActive Tff7b72= Te6edf3offlineOverlayEnabled Tff7b72&Tff7b72& Te6edf3attributionCoveringRegion Tff7b72!Tff7b72= Tff7b72null
Tff7b72val Te6edf3terrainActive Tff7b72=
Te6edf3attributionCoveringRegionTff7b72?.Te6edf3hasTerrain Tff7b72=Tff7b72= Tff7b72true Tff7b72&Tff7b72& Tb4b4b4(Te6edf3terrainHillshadeEnabled Tff7b72|Tff7b72| Te6edf3terrainContoursEnabledTb4b4b4)
Tff7b72val Te6edf3attributionText Tff7b72=
Te6edf3rememberTb4b4b4(Te6edf3currentRasterBasemapTb4b4b4, Te6edf3enabledOverlayIdsTb4b4b4, Te6edf3offlineRegionActiveTb4b4b4, Te6edf3terrainActiveTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3baseAttribution Tff7b72=
Te6edf3mapAttributionTextTb4b4b4(
Te6edf3basemap Tff7b72= Tb4b4b4(Te6edf3currentRasterBasemap Tff7b72as? Te6edf3RasterBasemapTb4b4b4.Te6edf3RemoteTb4b4b4)Tff7b72?.Te6edf3specTb4b4b4,
Te6edf3overlays Tff7b72= Te6edf3mapViewModelTb4b4b4.Te6edf3availableOverlaysTb4b4b4.Te6edf3filter Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3id Tff7b72in Te6edf3enabledOverlayIds Tb4b4b4}Tb4b4b4.Te6edf3map Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3spec Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Te6edf3buildList Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3baseAttributionTb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4)Tb4b4b4) Te6edf3addTb4b4b4(Te6edf3baseAttributionTb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3offlineRegionActiveTb4b4b4) Te6edf3addTb4b4b4(Te6edf3OfflineRegionExtractorTb4b4b4.Te6edf3ATTRIBUTIONTb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3terrainActiveTb4b4b4) Te6edf3addTb4b4b4(Te6edf3MapterhornEndpointsTb4b4b4.Te6edf3ATTRIBUTIONTb4b4b4)
Tb4b4b4}
Tb4b4b4.Te6edf3joinToStringTb4b4b4(Ta5d6ff"Ta5d6ff · Ta5d6ff"Tb4b4b4)
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3attributionTextTb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3TextTb4b4b4(
Te6edf3text Tff7b72= Te6edf3attributionTextTb4b4b4,
Te6edf3style Tff7b72= Te6edf3MaterialThemeTb4b4b4.Te6edf3typographyTb4b4b4.Te6edf3labelSmallTb4b4b4,
Te6edf3color Tff7b72= Te6edf3MaterialThemeTb4b4b4.Te6edf3colorSchemeTb4b4b4.Te6edf3onSurfaceVariantTb4b4b4,
Te6edf3modifier Tff7b72=
Te6edf3ModifierTb4b4b4.Te6edf3alignTb4b4b4(Te6edf3AlignmentTb4b4b4.Te6edf3BottomCenterTb4b4b4)
Tb4b4b4.Te6edf3paddingTb4b4b4(Te6edf3bottom Tff7b72= Te6edf3ATTRIBUTION_BOTTOM_PADDINGTb4b4b4)
Tb4b4b4.Te6edf3backgroundTb4b4b4(
Te6edf3MaterialThemeTb4b4b4.Te6edf3colorSchemeTb4b4b4.Te6edf3surfaceTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3alpha Tff7b72= Te6edf3ATTRIBUTION_SCRIM_ALPHATb4b4b4)Tb4b4b4,
Te6edf3MaterialThemeTb4b4b4.Te6edf3shapesTb4b4b4.Te6edf3extraSmallTb4b4b4,
Tb4b4b4)
Tb4b4b4.Te6edf3paddingTb4b4b4(Te6edf3horizontal Tff7b72= T79c0ff6.Te6edf3dpTb4b4b4, Te6edf3vertical Tff7b72= T79c0ff2.Te6edf3dpTb4b4b4)Tb4b4b4,
Tb4b4b4)
Tb4b4b4}

Te6edf3MapControlsOverlayTb4b4b4(
Te6edf3modifier Tff7b72= Te6edf3ModifierTb4b4b4.Te6edf3alignTb4b4b4(Te6edf3AlignmentTb4b4b4.Te6edf3TopCenterTb4b4b4)Tb4b4b4.Te6edf3paddingTb4b4b4(Te6edf3top Tff7b72= T79c0ff8.Te6edf3dpTb4b4b4)Tb4b4b4,
Te6edf3onToggleFilterMenu Tff7b72= Tb4b4b4{ Te6edf3mapFilterMenuExpanded Tff7b72= Tff7b72true Tb4b4b4}Tb4b4b4,
Te6edf3filtersActive Tff7b72= Te6edf3mode Tff7b72!is Te6edf3GoogleMapModeTb4b4b4.Te6edf3NodeTrack Tff7b72&Tff7b72& Te6edf3mapFilterStateTb4b4b4.Te6edf3isNarrowingTb4b4b4,
Te6edf3filterDropdownContent Tff7b72= Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3mode Tff7b72is Te6edf3GoogleMapModeTb4b4b4.Te6edf3NodeTrackTb4b4b4) Tb4b4b4{
Te6edf3NodeTrackFilterMenuTb4b4b4(
Te6edf3expanded Tff7b72= Te6edf3mapFilterMenuExpandedTb4b4b4,
Te6edf3onDismissRequest Tff7b72= Tb4b4b4{ Te6edf3mapFilterMenuExpanded Tff7b72= Tff7b72false Tb4b4b4}Tb4b4b4,
Te6edf3selected Tff7b72= Te6edf3mapFilterStateTb4b4b4.Te6edf3lastHeardTrackFilterTb4b4b4,
Te6edf3onSelect Tff7b72= Te6edf3mapViewModelTff7b72::Te6edf3setLastHeardTrackFilterTb4b4b4,
Tb4b4b4)
Tb4b4b4} Tff7b72else Tff7b72if Tb4b4b4(Te6edf3mapFilterMenuExpandedTb4b4b4) Tb4b4b4{
Te6edf3MapFilterSheetTb4b4b4(
Te6edf3onDismissRequest Tff7b72= Tb4b4b4{ Te6edf3mapFilterMenuExpanded Tff7b72= Tff7b72false Tb4b4b4}Tb4b4b4,
Te6edf3filterState Tff7b72= Te6edf3mapFilterStateTb4b4b4,
Te6edf3actions Tff7b72= Te6edf3mapViewModelTb4b4b4.Te6edf3mapFilterActionsTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}Tb4b4b4,
Te6edf3mapTypeContent Tff7b72= Tb4b4b4{
Te6edf3Box Tb4b4b4{
Te6edf3MapButtonTb4b4b4(
Te6edf3icon Tff7b72= Te6edf3MeshtasticIconsTb4b4b4.Te6edf3MapTb4b4b4,
Te6edf3contentDescription Tff7b72= Te6edf3stringResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3map_tile_sourceTb4b4b4)Tb4b4b4,
Te6edf3onClick Tff7b72= Tb4b4b4{ Te6edf3mapTypeMenuExpanded Tff7b72= Tff7b72true Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Te6edf3MapTypeDropdownTb4b4b4(
Te6edf3expanded Tff7b72= Te6edf3mapTypeMenuExpandedTb4b4b4,
Te6edf3onDismissRequest Tff7b72= Tb4b4b4{ Te6edf3mapTypeMenuExpanded Tff7b72= Tff7b72false Tb4b4b4}Tb4b4b4,
Te6edf3mapViewModel Tff7b72= Te6edf3mapViewModelTb4b4b4,
Te6edf3onManageCustomTileProvidersClick Tff7b72= Tb4b4b4{
Te6edf3mapTypeMenuExpanded Tff7b72= Tff7b72false
Te6edf3showCustomTileManagerSheet Tff7b72= Tff7b72true
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}Tb4b4b4,
Te6edf3layersContent Tff7b72= Tb4b4b4{
Te6edf3MapButtonTb4b4b4(
Te6edf3icon Tff7b72= Te6edf3MeshtasticIconsTb4b4b4.Te6edf3LayersTb4b4b4,
Te6edf3contentDescription Tff7b72= Te6edf3stringResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3manage_map_layersTb4b4b4)Tb4b4b4,
Te6edf3onClick Tff7b72= Tb4b4b4{ Te6edf3showLayersBottomSheet Tff7b72= Tff7b72true Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tb4b4b4}Tb4b4b4,
T8b949e// Hands params to the hosted Site Planner and imports the returned coverage.
Te6edf3onSitePlannerClick Tff7b72= Tb4b4b4{
Te6edf3sitePlannerLaunch Tff7b72= Te6edf3SitePlannerLaunchTb4b4b4(Te6edf3initialParams Tff7b72= Te6edf3ourNodeInfoTb4b4b4.Te6edf3toSitePlannerParamsTb4b4b4(Te6edf3channelSetTb4b4b4)Tb4b4b4)
Tb4b4b4}Tb4b4b4,
Te6edf3isLocationTrackingEnabled Tff7b72= Te6edf3isLocationTrackingEnabledTb4b4b4,
Te6edf3onToggleLocationTracking Tff7b72= Tb4b4b4{
Tff7b72when Tb4b4b4{
Te6edf3locationPermissionTb4b4b4.Te6edf3isGranted Tff7b72-Tff7b72> Tb4b4b4{
Te6edf3isLocationTrackingEnabled Tff7b72= Tff7b72!Te6edf3isLocationTrackingEnabled
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3isLocationTrackingEnabledTb4b4b4) Tb4b4b4{
Te6edf3followPhoneBearing Tff7b72= Tff7b72false
Tb4b4b4}
Tb4b4b4}

T8b949e// Permanently denied: the system won't prompt again, so send the user to settings to recover.
Te6edf3locationPermissionTb4b4b4.Te6edf3status Tff7b72=Tff7b72= Te6edf3PermissionStatusTb4b4b4.Te6edf3PERMANENTLY_DENIED Tff7b72-Tff7b72>
Te6edf3locationPermissionTb4b4b4.Te6edf3openAppSettingsTb4b4b4(Tb4b4b4)

Tff7b72else Tff7b72-Tff7b72> Tb4b4b4{
Te6edf3triggerLocationToggleAfterPermission Tff7b72= Tff7b72true
Te6edf3locationPermissionTb4b4b4.Te6edf3requestTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}Tb4b4b4,
Te6edf3bearing Tff7b72= Te6edf3cameraPositionStateTb4b4b4.Te6edf3positionTb4b4b4.Te6edf3bearingTb4b4b4,
Te6edf3onCompassClick Tff7b72= Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3isLocationTrackingEnabledTb4b4b4) Tb4b4b4{
Te6edf3followPhoneBearing Tff7b72= Tff7b72!Te6edf3followPhoneBearing
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3coroutineScopeTb4b4b4.Te6edf3launch Tb4b4b4{
Tff7b72try Tb4b4b4{
Tff7b72val Te6edf3currentPosition Tff7b72= Te6edf3cameraPositionStateTb4b4b4.Te6edf3position
Tff7b72val Te6edf3newCameraPosition Tff7b72= Te6edf3CameraPositionTb4b4b4.Te6edf3BuilderTb4b4b4(Te6edf3currentPositionTb4b4b4)Tb4b4b4.Te6edf3bearingTb4b4b4(T79c0ff0fTb4b4b4)Tb4b4b4.Te6edf3buildTb4b4b4(Tb4b4b4)
Te6edf3cameraPositionStateTb4b4b4.Te6edf3animateTb4b4b4(Te6edf3CameraUpdateFactoryTb4b4b4.Te6edf3newCameraPositionTb4b4b4(Te6edf3newCameraPositionTb4b4b4)Tb4b4b4)
Te6edf3LoggerTb4b4b4.Te6edf3d Tb4b4b4{ Ta5d6ff"Ta5d6ffOriented map to northTa5d6ff" Tb4b4b4}
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3IllegalStateExceptionTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3d Tb4b4b4{ Ta5d6ff"Ta5d6ffError orienting map to north: Tffd700${Te6edf3eTb4b4b4.Te6edf3messageTffd700}Ta5d6ff" Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}Tb4b4b4,
Te6edf3followPhoneBearing Tff7b72= Te6edf3followPhoneBearingTb4b4b4,
Te6edf3showRefresh Tff7b72= Te6edf3showRefreshTb4b4b4,
Te6edf3isRefreshing Tff7b72= Te6edf3isRefreshingLayersTb4b4b4,
Te6edf3onRefresh Tff7b72= Tb4b4b4{ Te6edf3mapViewModelTb4b4b4.Te6edf3refreshAllVisibleNetworkLayersTb4b4b4(Tb4b4b4) Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tb4b4b4}

T8b949e// --- Bottom sheets & dialogs ---
Tff7b72if Tb4b4b4(Te6edf3showLayersBottomSheetTb4b4b4) Tb4b4b4{
Te6edf3ModalBottomSheetTb4b4b4(
Te6edf3onDismissRequest Tff7b72= Tb4b4b4{
Te6edf3showLayersBottomSheet Tff7b72= Tff7b72false
Te6edf3mapViewModelTb4b4b4.Te6edf3clearOfflineDownloadStateTb4b4b4(Tb4b4b4)
Te6edf3mapViewModelTb4b4b4.Te6edf3clearTerrainDownloadStateTb4b4b4(Tb4b4b4)
Tb4b4b4}Tb4b4b4,
Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3offlineRegions Tff7b72by Te6edf3mapViewModelTb4b4b4.Te6edf3offlineRegionsTb4b4b4.Te6edf3collectAsStateWithLifecycleTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3offlineDownloadState Tff7b72by Te6edf3mapViewModelTb4b4b4.Te6edf3offlineDownloadStateTb4b4b4.Te6edf3collectAsStateWithLifecycleTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3terrainDownloadState Tff7b72by Te6edf3mapViewModelTb4b4b4.Te6edf3terrainDownloadStateTb4b4b4.Te6edf3collectAsStateWithLifecycleTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3terrainDownloadRegionId Tff7b72by Te6edf3mapViewModelTb4b4b4.Te6edf3terrainDownloadRegionIdTb4b4b4.Te6edf3collectAsStateWithLifecycleTb4b4b4(Tb4b4b4)
Te6edf3OfflineRegionManagerSectionTb4b4b4(
Te6edf3visibleBounds Tff7b72= Te6edf3cameraPositionStateTb4b4b4.Te6edf3projectionTff7b72?.Te6edf3visibleRegionTff7b72?.Te6edf3latLngBoundsTb4b4b4,
Te6edf3currentZoom Tff7b72= Te6edf3cameraPositionStateTb4b4b4.Te6edf3positionTb4b4b4.Te6edf3zoomTb4b4b4.Te6edf3toIntTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3regions Tff7b72= Te6edf3offlineRegionsTb4b4b4,
Te6edf3downloadState Tff7b72= Te6edf3offlineDownloadStateTb4b4b4,
Te6edf3offlineOverlayEnabled Tff7b72= Te6edf3offlineOverlayEnabledTb4b4b4,
Te6edf3estimateTileCount Tff7b72= Te6edf3mapViewModelTff7b72::Te6edf3estimateOfflineTileCountTb4b4b4,
Te6edf3onDownload Tff7b72= Te6edf3mapViewModelTff7b72::Te6edf3downloadOfflineRegionTb4b4b4,
Te6edf3onDeleteRegion Tff7b72= Te6edf3mapViewModelTff7b72::Te6edf3deleteOfflineRegionTb4b4b4,
Te6edf3onToggleOfflineOverlay Tff7b72= Te6edf3mapViewModelTff7b72::Te6edf3setOfflineOverlayEnabledTb4b4b4,
Te6edf3terrainDownloadState Tff7b72= Te6edf3terrainDownloadStateTb4b4b4,
Te6edf3terrainDownloadRegionId Tff7b72= Te6edf3terrainDownloadRegionIdTb4b4b4,
Te6edf3terrainHillshadeEnabled Tff7b72= Te6edf3terrainHillshadeEnabledTb4b4b4,
Te6edf3terrainContoursEnabled Tff7b72= Te6edf3terrainContoursEnabledTb4b4b4,
Te6edf3onDownloadTerrain Tff7b72= Te6edf3mapViewModelTff7b72::Te6edf3downloadTerrainForRegionTb4b4b4,
Te6edf3onToggleHillshade Tff7b72= Te6edf3mapViewModelTff7b72::Te6edf3setTerrainHillshadeEnabledTb4b4b4,
Te6edf3onToggleContours Tff7b72= Te6edf3mapViewModelTff7b72::Te6edf3setTerrainContoursEnabledTb4b4b4,
Tb4b4b4)
Te6edf3HorizontalDividerTb4b4b4(Tb4b4b4)

T8b949e// The raster overlays sit above the imported-layer manager, matching where the MapLibre map puts them.
Te6edf3RasterOverlayTogglesTb4b4b4(
Te6edf3available Tff7b72= Te6edf3mapViewModelTb4b4b4.Te6edf3availableOverlaysTb4b4b4,
Te6edf3enabledIds Tff7b72= Te6edf3enabledOverlayIdsTb4b4b4,
Te6edf3onToggle Tff7b72= Tb4b4b4{ Te6edf3mapViewModelTb4b4b4.Te6edf3toggleOverlayTb4b4b4(Tffa657itTb4b4b4) Tb4b4b4}Tb4b4b4,
Te6edf3opacity Tff7b72= Te6edf3layerOpacityTb4b4b4,
Te6edf3onOpacityChange Tff7b72= Tb4b4b4{ Te6edf3keyTb4b4b4, Te6edf3value Tff7b72-Tff7b72> Te6edf3mapViewModelTb4b4b4.Te6edf3setLayerOpacityTb4b4b4(Te6edf3keyTb4b4b4, Te6edf3valueTb4b4b4) Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Te6edf3HorizontalDividerTb4b4b4(Tb4b4b4)
Te6edf3CustomMapLayersSheetTb4b4b4(
Te6edf3mapLayers Tff7b72= Te6edf3mapLayersTb4b4b4,
Te6edf3onToggleVisibility Tff7b72= Te6edf3onToggleVisibilityTb4b4b4,
Te6edf3onRemoveLayer Tff7b72= Te6edf3onRemoveLayerTb4b4b4,
Te6edf3onAddLayerClicked Tff7b72= Te6edf3onAddLayerClickedTb4b4b4,
Te6edf3onRefreshLayer Tff7b72= Tb4b4b4{ Te6edf3mapViewModelTb4b4b4.Te6edf3refreshMapLayerTb4b4b4(Tffa657itTb4b4b4) Tb4b4b4}Tb4b4b4,
Te6edf3onAddNetworkLayer Tff7b72= Tb4b4b4{ Te6edf3nameTb4b4b4, Te6edf3url Tff7b72-Tff7b72> Te6edf3mapViewModelTb4b4b4.Te6edf3addNetworkMapLayerTb4b4b4(Te6edf3nameTb4b4b4, Te6edf3urlTb4b4b4) Tb4b4b4}Tb4b4b4,
Te6edf3opacity Tff7b72= Te6edf3layerOpacityTb4b4b4,
Te6edf3onOpacityChange Tff7b72= Tb4b4b4{ Te6edf3keyTb4b4b4, Te6edf3value Tff7b72-Tff7b72> Te6edf3mapViewModelTb4b4b4.Te6edf3setLayerOpacityTb4b4b4(Te6edf3keyTb4b4b4, Te6edf3valueTb4b4b4) Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
T8b949e// Site Planner deep link from a node's detail screen — open the estimate dialog prefilled with that node.
Tff7b72val Te6edf3sitePlannerRequest Tff7b72by Te6edf3mapViewModelTb4b4b4.Te6edf3sitePlannerRequestTb4b4b4.Te6edf3collectAsStateWithLifecycleTb4b4b4(Tb4b4b4)
Te6edf3LaunchedEffectTb4b4b4(Te6edf3sitePlannerRequestTb4b4b4) Tb4b4b4{
Te6edf3sitePlannerRequestTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3node Tff7b72-Tff7b72>
Te6edf3sitePlannerLaunch Tff7b72=
Te6edf3SitePlannerLaunchTb4b4b4(Te6edf3initialParams Tff7b72= Te6edf3nodeTb4b4b4.Te6edf3toSitePlannerParamsTb4b4b4(Te6edf3channelSetTb4b4b4)Tb4b4b4, Te6edf3selectedNode Tff7b72= Te6edf3nodeTb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3nodeTb4b4b4.Te6edf3validPosition Tff7b72!Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Te6edf3cameraPositionStateTb4b4b4.Te6edf3animateTb4b4b4(Te6edf3CameraUpdateFactoryTb4b4b4.Te6edf3newLatLngTb4b4b4(Te6edf3LatLngTb4b4b4(Te6edf3nodeTb4b4b4.Te6edf3latitudeTb4b4b4, Te6edf3nodeTb4b4b4.Te6edf3longitudeTb4b4b4)Tb4b4b4)Tb4b4b4)
Tb4b4b4}
Te6edf3mapViewModelTb4b4b4.Te6edf3consumeSitePlannerRequestTb4b4b4(Te6edf3nodeTb4b4b4.Te6edf3numTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Te6edf3sitePlannerLaunchTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3launch Tff7b72-Tff7b72>
T8b949e// Phone GPS: only when permission is already granted; otherwise the field stays manual.
Tff7b72val Te6edf3onRequestCurrentLocationTb4b4b4: Tb4b4b4(Te6edf3suspend Tb4b4b4(Tb4b4b4) Tff7b72-Tff7b72> Te6edf3PairTff7b72<Tffa657DoubleTb4b4b4, Tffa657DoubleTff7b72>Tff7b72?Tb4b4b4)Tff7b72? Tff7b72=
Tff7b72if Tb4b4b4(Te6edf3locationPermissionTb4b4b4.Te6edf3isGrantedTb4b4b4) Tb4b4b4{
Tb4b4b4{ Te6edf3fusedLocationClientTb4b4b4.Te6edf3awaitLastLocationTb4b4b4(Tb4b4b4)Tff7b72?.Te6edf3let Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3latitude Te6edf3to Tffa657itTb4b4b4.Te6edf3longitude Tb4b4b4} Tb4b4b4}
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72null
Tb4b4b4}
T8b949e// Route launches retain the selected node; manual map launches continue following our connected node.
Tff7b72val Te6edf3onUseNodeLocationTb4b4b4: Tb4b4b4(Tb4b4b4(Tb4b4b4) Tff7b72-Tff7b72> Te6edf3PairTff7b72<Tffa657DoubleTb4b4b4, Tffa657DoubleTff7b72>Tb4b4b4)Tff7b72? Tff7b72=
Te6edf3launchTb4b4b4.Te6edf3nodeLocationTb4b4b4(Te6edf3ourNodeInfoTb4b4b4)Tff7b72?.Te6edf3let Tb4b4b4{ Te6edf3location Tff7b72-Tff7b72> Tb4b4b4{ Te6edf3location Tb4b4b4} Tb4b4b4}
Te6edf3SitePlannerHostTb4b4b4(
Te6edf3initialParams Tff7b72= Te6edf3launchTb4b4b4.Te6edf3initialParamsTb4b4b4,
Te6edf3onDismiss Tff7b72= Tb4b4b4{ Te6edf3sitePlannerLaunch Tff7b72= Tff7b72null Tb4b4b4}Tb4b4b4,
Te6edf3onImport Tff7b72= Tb4b4b4{ Te6edf3nameTb4b4b4, Te6edf3geoJsonTb4b4b4, Te6edf3latitudeTb4b4b4, Te6edf3longitude Tff7b72-Tff7b72>
Te6edf3mapViewModelTb4b4b4.Te6edf3addGeoJsonLayerTb4b4b4(Te6edf3nameTb4b4b4, Te6edf3geoJsonTb4b4b4)
T8b949e// Recenter on the estimate's transmitter so the freshly-imported coverage is on-screen.
Te6edf3coroutineScopeTb4b4b4.Te6edf3launch Tb4b4b4{
Te6edf3cameraPositionStateTb4b4b4.Te6edf3animateTb4b4b4(Te6edf3CameraUpdateFactoryTb4b4b4.Te6edf3newLatLngTb4b4b4(Te6edf3LatLngTb4b4b4(Te6edf3latitudeTb4b4b4, Te6edf3longitudeTb4b4b4)Tb4b4b4)Tb4b4b4)
Tb4b4b4}
Tb4b4b4}Tb4b4b4,
Te6edf3onRequestCurrentLocation Tff7b72= Te6edf3onRequestCurrentLocationTb4b4b4,
Te6edf3onUseNodeLocation Tff7b72= Te6edf3onUseNodeLocationTb4b4b4,
Te6edf3onUseMapCenter Tff7b72= Tb4b4b4{ Te6edf3cameraPositionStateTb4b4b4.Te6edf3positionTb4b4b4.Te6edf3targetTb4b4b4.Te6edf3let Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3latitude Te6edf3to Tffa657itTb4b4b4.Te6edf3longitude Tb4b4b4} Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Te6edf3showClusterItemsDialogTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3items Tff7b72-Tff7b72>
Te6edf3ClusterMembersDialogTb4b4b4(
Te6edf3members Tff7b72=
Te6edf3itemsTb4b4b4.Te6edf3map Tb4b4b4{
Te6edf3ClusterMemberEntryTb4b4b4(
Te6edf3nodeNum Tff7b72= Tffa657itTb4b4b4.Te6edf3nodeTb4b4b4.Te6edf3numTb4b4b4,
Te6edf3title Tff7b72= Tffa657itTb4b4b4.Te6edf3nodeTitleTb4b4b4,
Te6edf3subtitle Tff7b72= Tffa657itTb4b4b4.Te6edf3nodeSnippetTb4b4b4,
Te6edf3node Tff7b72= Tffa657itTb4b4b4.Te6edf3nodeTb4b4b4,
Tb4b4b4)
Tb4b4b4}Tb4b4b4,
Te6edf3onMemberClick Tff7b72= Tb4b4b4{ Te6edf3nodeNum Tff7b72-Tff7b72>
Te6edf3navigateToNodeDetailsTb4b4b4(Te6edf3nodeNumTb4b4b4)
Te6edf3showClusterItemsDialog Tff7b72= Tff7b72null
Tb4b4b4}Tb4b4b4,
Te6edf3onDismissRequest Tff7b72= Tb4b4b4{ Te6edf3showClusterItemsDialog Tff7b72= Tff7b72null Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3showCustomTileManagerSheetTb4b4b4) Tb4b4b4{
Te6edf3ModalBottomSheetTb4b4b4(Te6edf3onDismissRequest Tff7b72= Tb4b4b4{ Te6edf3showCustomTileManagerSheet Tff7b72= Tff7b72false Tb4b4b4}Tb4b4b4) Tb4b4b4{
Te6edf3CustomTileProviderManagerSheetTb4b4b4(Te6edf3mapViewModel Tff7b72= Te6edf3mapViewModelTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Tff7b72private Tff7b72const Tff7b72val Te6edf3SECONDS_PER_MINUTE Tff7b72= T79c0ff6T79c0ff0L
Tff7b72private Tff7b72const Tff7b72val Te6edf3MILLIS_PER_SECOND Tff7b72= T79c0ff1Te6edf3_000L

Tf0883e@Composable
Tff7b72private Tff7b72fun Td2a8ffrememberRelativeTimeBucketTb4b4b4(Tb4b4b4)Tb4b4b4: Tffa657Long Tb4b4b4{
Tff7b72val Te6edf3buckets Tff7b72= Te6edf3remember Tb4b4b4{ Te6edf3relativeTimeBucketsTb4b4b4(Tb4b4b4) Tb4b4b4}
Tff7b72return Te6edf3bucketsTb4b4b4.Te6edf3collectAsStateWithLifecycleTb4b4b4(Te6edf3initialValue Tff7b72= Te6edf3nowSeconds Tff7b72/ Te6edf3SECONDS_PER_MINUTETb4b4b4)Tb4b4b4.Te6edf3value
Tb4b4b4}

Tff7b72internal Tff7b72fun Td2a8ffrelativeTimeBucketsTb4b4b4(Te6edf3nowTb4b4b4: Tb4b4b4(Tb4b4b4) Tff7b72-Tff7b72> Tffa657Long Tff7b72= Tb4b4b4{ Te6edf3nowSeconds Tb4b4b4}Tb4b4b4)Tb4b4b4: Te6edf3FlowTff7b72<Tffa657LongTff7b72> Tff7b72= Te6edf3flow Tb4b4b4{
Tff7b72while Tb4b4b4(Tff7b72trueTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3currentSeconds Tff7b72= Te6edf3nowTb4b4b4(Tb4b4b4)
Te6edf3emitTb4b4b4(Te6edf3currentSeconds Tff7b72/ Te6edf3SECONDS_PER_MINUTETb4b4b4)
Tff7b72val Te6edf3secondsUntilNextMinute Tff7b72= Te6edf3SECONDS_PER_MINUTE Tff7b72- Te6edf3currentSecondsTb4b4b4.Te6edf3modTb4b4b4(Te6edf3SECONDS_PER_MINUTETb4b4b4)
Te6edf3delayTb4b4b4(Te6edf3secondsUntilNextMinute Tff7b72* Te6edf3MILLIS_PER_SECONDTb4b4b4)
Tb4b4b4}
Tb4b4b4}

T8b949e/**
* Materializes the native clustering model used by the Google map.
*
* Camera state invalidates [MapView] on every movement frame, and its filters produce a new-but-equal [List] each time.
* Using that structural value as a key avoids rebuilding every [NodeClusterItem] (and its strings/[LatLng]) for
* camera-only changes. [relativeTimeBucket] deliberately refreshes the relative marker titles once per minute.
*/
Tf0883e@Composable
Tff7b72internal Tff7b72fun Td2a8ffrememberNodeClusterItemsTb4b4b4(
Te6edf3nodesTb4b4b4: Te6edf3ListTff7b72<Te6edf3NodeTff7b72>Tb4b4b4,
Te6edf3myNodeNumTb4b4b4: Tffa657Int?Tb4b4b4,
Te6edf3relativeTimeBucketTb4b4b4: Tffa657LongTb4b4b4,
Tb4b4b4)Tb4b4b4: Te6edf3ListTff7b72<Te6edf3NodeClusterItemTff7b72> Tb4b4b4{
Tff7b72val Te6edf3unknownText Tff7b72= Te6edf3stringResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3unknownTb4b4b4)
Tff7b72val Te6edf3nowText Tff7b72= Te6edf3stringResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3nowTb4b4b4)
Tff7b72return Te6edf3rememberTb4b4b4(Te6edf3nodesTb4b4b4, Te6edf3myNodeNumTb4b4b4, Te6edf3relativeTimeBucketTb4b4b4, Te6edf3unknownTextTb4b4b4, Te6edf3nowTextTb4b4b4) Tb4b4b4{
Te6edf3nodesTb4b4b4.Te6edf3map Tb4b4b4{ Te6edf3node Tff7b72-Tff7b72>
Tff7b72val Te6edf3latLng Tff7b72= Te6edf3LatLngTb4b4b4(Tb4b4b4(Te6edf3nodeTb4b4b4.Te6edf3positionTb4b4b4.Te6edf3latitude_i Tff7b72?: T79c0ff0Tb4b4b4) Tff7b72* Te6edf3DEG_DTb4b4b4, Tb4b4b4(Te6edf3nodeTb4b4b4.Te6edf3positionTb4b4b4.Te6edf3longitude_i Tff7b72?: T79c0ff0Tb4b4b4) Tff7b72* Te6edf3DEG_DTb4b4b4)
Te6edf3NodeClusterItemTb4b4b4(
Te6edf3node Tff7b72= Te6edf3nodeTb4b4b4,
Te6edf3nodePosition Tff7b72= Te6edf3latLngTb4b4b4,
Te6edf3nodeTitle Tff7b72= Ta5d6ff"Tffd700${Te6edf3nodeTb4b4b4.Te6edf3userTb4b4b4.Te6edf3short_nameTffd700}Ta5d6ff Tffd700${Te6edf3formatAgoTb4b4b4(Te6edf3nodeTb4b4b4.Te6edf3positionTb4b4b4.Te6edf3timeTb4b4b4, Te6edf3unknownTextTb4b4b4, Te6edf3nowTextTb4b4b4)Tffd700}Ta5d6ff"Tb4b4b4,
Te6edf3nodeSnippet Tff7b72= Te6edf3nodeTb4b4b4.Te6edf3userTb4b4b4.Te6edf3long_nameTb4b4b4,
Te6edf3myNodeNum Tff7b72= Te6edf3myNodeNumTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

T8b949e// region --- Main Map Content ---

Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffLongParameterListTa5d6ff"Tb4b4b4)
Tf0883e@OptInTb4b4b4(Te6edf3MapsComposeExperimentalApiTff7b72::Te6edf3classTb4b4b4)
Tf0883e@Composable
Tff7b72private Tff7b72fun Td2a8ffMainMapContentTb4b4b4(
Te6edf3nodeClusterItemsTb4b4b4: Te6edf3ListTff7b72<Te6edf3NodeClusterItemTff7b72>Tb4b4b4,
Te6edf3mapFilterStateTb4b4b4: Te6edf3MapFilterStateTb4b4b4,
Te6edf3navigateToNodeDetailsTb4b4b4: Tb4b4b4(Tffa657IntTb4b4b4) Tff7b72-Tff7b72> Tffa657UnitTb4b4b4,
Te6edf3displayableWaypointsTb4b4b4: Te6edf3ListTff7b72<Te6edf3WaypointTff7b72>Tb4b4b4,
Te6edf3myNodeNumTb4b4b4: Tffa657Int?Tb4b4b4,
Te6edf3onEditWaypointRequestTb4b4b4: Tb4b4b4(Te6edf3WaypointTb4b4b4) Tff7b72-Tff7b72> Tffa657UnitTb4b4b4,
Te6edf3onDeleteWaypointRequestTb4b4b4: Tb4b4b4(Te6edf3WaypointTb4b4b4) Tff7b72-Tff7b72> Tffa657UnitTb4b4b4,
Te6edf3onShowGeofenceInfoTb4b4b4: Tb4b4b4(Te6edf3WaypointTb4b4b4) Tff7b72-Tff7b72> Tffa657UnitTb4b4b4,
Te6edf3selectedWaypointIdTb4b4b4: Tffa657Int?Tb4b4b4,
Te6edf3mapLayersTb4b4b4: Te6edf3ListTff7b72<Te6edf3MapLayerItemTff7b72>Tb4b4b4,
Te6edf3layerOpacityTb4b4b4: Te6edf3MapTff7b72<Tffa657StringTb4b4b4, Tffa657FloatTff7b72>Tb4b4b4,
Te6edf3mapViewModelTb4b4b4: Te6edf3MapViewModelTb4b4b4,
Te6edf3cameraPositionStateTb4b4b4: Te6edf3CameraPositionStateTb4b4b4,
Te6edf3coroutineScopeTb4b4b4: Te6edf3CoroutineScopeTb4b4b4,
Te6edf3onShowClusterItemsDialogTb4b4b4: Tb4b4b4(Te6edf3ListTff7b72<Te6edf3NodeClusterItemTff7b72>Tff7b72?Tb4b4b4) Tff7b72-Tff7b72> Tffa657UnitTb4b4b4,
Tb4b4b4) Tb4b4b4{
Te6edf3NodeClusterMarkersTb4b4b4(
Te6edf3nodeClusterItems Tff7b72= Te6edf3nodeClusterItemsTb4b4b4,
Te6edf3mapFilterState Tff7b72= Te6edf3mapFilterStateTb4b4b4,
Te6edf3navigateToNodeDetails Tff7b72= Te6edf3navigateToNodeDetailsTb4b4b4,
Te6edf3onClusterClick Tff7b72= Tb4b4b4{ Te6edf3cluster Tff7b72-Tff7b72>
Tff7b72val Te6edf3items Tff7b72= Te6edf3clusterTb4b4b4.Te6edf3itemsTb4b4b4.Te6edf3toListTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3allSameLocation Tff7b72= Te6edf3itemsTb4b4b4.Te6edf3size Tff7b72> T79c0ff1 Tff7b72&Tff7b72& Te6edf3itemsTb4b4b4.Te6edf3all Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3position Tff7b72=Tff7b72= Te6edf3itemsTb4b4b4.Te6edf3firstTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3position Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3allSameLocationTb4b4b4) Tb4b4b4{
Te6edf3onShowClusterItemsDialogTb4b4b4(Te6edf3itemsTb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72val Te6edf3bounds Tff7b72= Te6edf3LatLngBoundsTb4b4b4.Te6edf3builderTb4b4b4(Tb4b4b4)
Te6edf3clusterTb4b4b4.Te6edf3itemsTb4b4b4.Te6edf3forEach Tb4b4b4{ Te6edf3boundsTb4b4b4.Te6edf3includeTb4b4b4(Tffa657itTb4b4b4.Te6edf3positionTb4b4b4) Tb4b4b4}
Te6edf3coroutineScopeTb4b4b4.Te6edf3launch Tb4b4b4{
Te6edf3cameraPositionStateTb4b4b4.Te6edf3animateTb4b4b4(
Te6edf3CameraUpdateFactoryTb4b4b4.Te6edf3newCameraPositionTb4b4b4(
Te6edf3CameraPositionTb4b4b4.Te6edf3BuilderTb4b4b4(Tb4b4b4)
Tb4b4b4.Te6edf3targetTb4b4b4(Te6edf3boundsTb4b4b4.Te6edf3buildTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3centerTb4b4b4)
Tb4b4b4.Te6edf3zoomTb4b4b4(Te6edf3cameraPositionStateTb4b4b4.Te6edf3positionTb4b4b4.Te6edf3zoom Tff7b72+ T79c0ff1Tb4b4b4)
Tb4b4b4.Te6edf3buildTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Te6edf3LoggerTb4b4b4.Te6edf3d Tb4b4b4{ Ta5d6ff"Ta5d6ffCluster clicked! Tffd700$Te6edf3clusterTa5d6ff" Tb4b4b4}
Tb4b4b4}
Tff7b72true
Tb4b4b4}Tb4b4b4,
Tb4b4b4)

Te6edf3WaypointMarkersTb4b4b4(
Te6edf3displayableWaypoints Tff7b72= Te6edf3displayableWaypointsTb4b4b4,
Te6edf3mapFilterState Tff7b72= Te6edf3mapFilterStateTb4b4b4,
Te6edf3myNodeNum Tff7b72= Te6edf3myNodeNum Tff7b72?: T79c0ff0Tb4b4b4,
Te6edf3onEditWaypointRequest Tff7b72= Te6edf3onEditWaypointRequestTb4b4b4,
Te6edf3onDeleteWaypointRequest Tff7b72= Te6edf3onDeleteWaypointRequestTb4b4b4,
Te6edf3isMyWaypoint Tff7b72= Te6edf3mapViewModelTff7b72::Te6edf3isMyWaypointTb4b4b4,
Te6edf3onShowGeofenceInfo Tff7b72= Te6edf3onShowGeofenceInfoTb4b4b4,
Te6edf3selectedWaypointId Tff7b72= Te6edf3selectedWaypointIdTb4b4b4,
Tb4b4b4)

Tff7b72if Tb4b4b4(Te6edf3mapFilterStateTb4b4b4.Te6edf3showWaypointsTb4b4b4) Tb4b4b4{
Te6edf3displayableWaypointsTb4b4b4.Te6edf3forEach Tb4b4b4{ Te6edf3waypoint Tff7b72-Tff7b72> Te6edf3WaypointGeofenceOverlayTb4b4b4(Te6edf3waypointTb4b4b4) Tb4b4b4}
Tb4b4b4}

Te6edf3mapLayersTb4b4b4.Te6edf3forEach Tb4b4b4{ Te6edf3layerItem Tff7b72-Tff7b72>
Tff7b72val Te6edf3opacity Tff7b72= Te6edf3layerItemTb4b4b4.Te6edf3uriTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3layerOpacityTb4b4b4.Te6edf3opacityOfTb4b4b4(Tffa657itTb4b4b4) Tb4b4b4} Tff7b72?: T79c0ff1f
Te6edf3keyTb4b4b4(Te6edf3layerItemTb4b4b4.Te6edf3idTb4b4b4) Tb4b4b4{ Te6edf3MapLayerOverlayTb4b4b4(Te6edf3layerItemTb4b4b4, Te6edf3opacityTb4b4b4, Te6edf3mapViewModelTb4b4b4) Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

T8b949e/**
* Draws this waypoint's geofence region: a [Circle] for a radius geofence and/or a [Polygon] for a bounding box. Uses
* the shared [toGeofence] decoder so the coordinate math stays in one place. Renders nothing when no region is set.
*/
Tf0883e@Composable
Tff7b72private Tff7b72fun Td2a8ffWaypointGeofenceOverlayTb4b4b4(Te6edf3waypointTb4b4b4: Te6edf3WaypointTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3geofence Tff7b72= Te6edf3waypointTb4b4b4.Te6edf3toGeofenceTb4b4b4(Tb4b4b4) Tff7b72?: Tff7b72return
Te6edf3geofenceTb4b4b4.Te6edf3circleTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3circle Tff7b72-Tff7b72>
Te6edf3CircleTb4b4b4(
Te6edf3center Tff7b72= Te6edf3LatLngTb4b4b4(Te6edf3circleTb4b4b4.Te6edf3centerLatTb4b4b4, Te6edf3circleTb4b4b4.Te6edf3centerLonTb4b4b4)Tb4b4b4,
Te6edf3radius Tff7b72= Te6edf3circleTb4b4b4.Te6edf3radiusMetersTb4b4b4.Te6edf3toDoubleTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3strokeColor Tff7b72= Te6edf3GEOFENCE_OVERLAY_COLORTb4b4b4,
Te6edf3fillColor Tff7b72= Te6edf3GEOFENCE_OVERLAY_COLORTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3alpha Tff7b72= Te6edf3GEOFENCE_FILL_ALPHATb4b4b4)Tb4b4b4,
Te6edf3strokeWidth Tff7b72= Te6edf3GEOFENCE_STROKE_WIDTHTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Te6edf3geofenceTb4b4b4.Te6edf3boxTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3box Tff7b72-Tff7b72>
Te6edf3PolygonTb4b4b4(
Te6edf3points Tff7b72=
Te6edf3listOfTb4b4b4(
Te6edf3LatLngTb4b4b4(Te6edf3boxTb4b4b4.Te6edf3southTb4b4b4, Te6edf3boxTb4b4b4.Te6edf3westTb4b4b4)Tb4b4b4,
Te6edf3LatLngTb4b4b4(Te6edf3boxTb4b4b4.Te6edf3northTb4b4b4, Te6edf3boxTb4b4b4.Te6edf3westTb4b4b4)Tb4b4b4,
Te6edf3LatLngTb4b4b4(Te6edf3boxTb4b4b4.Te6edf3northTb4b4b4, Te6edf3boxTb4b4b4.Te6edf3eastTb4b4b4)Tb4b4b4,
Te6edf3LatLngTb4b4b4(Te6edf3boxTb4b4b4.Te6edf3southTb4b4b4, Te6edf3boxTb4b4b4.Te6edf3eastTb4b4b4)Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Te6edf3strokeColor Tff7b72= Te6edf3GEOFENCE_OVERLAY_COLORTb4b4b4,
Te6edf3fillColor Tff7b72= Te6edf3GEOFENCE_OVERLAY_COLORTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3alpha Tff7b72= Te6edf3GEOFENCE_FILL_ALPHATb4b4b4)Tb4b4b4,
Te6edf3strokeWidth Tff7b72= Te6edf3GEOFENCE_STROKE_WIDTHTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}

T8b949e// endregion

T8b949e// region --- Node Track Overlay ---

T8b949e/**
* Renders the position track polyline segments and markers inside a [GoogleMap] content scope. Each marker fades from
* transparent (oldest) to opaque (newest). The newest position shows the node's [NodeChip]; older positions show a
* [TripOrigin] dot with an info-window on tap.
*
* When [selectedPositionTime] matches a marker's `Position.time`, that marker is highlighted with the primary color and
* elevated z-index. Tapping a marker invokes [onPositionSelect] for list synchronization.
*/
Tf0883e@OptInTb4b4b4(Te6edf3MapsComposeExperimentalApiTff7b72::Te6edf3classTb4b4b4)
Tf0883e@Composable
Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffLongMethodTa5d6ff"Tb4b4b4)
Tff7b72private Tff7b72fun Td2a8ffNodeTrackOverlayTb4b4b4(
Te6edf3focusedNodeTb4b4b4: Te6edf3NodeTb4b4b4,
Te6edf3sortedPositionsTb4b4b4: Te6edf3ListTff7b72<Te6edf3PositionTff7b72>Tb4b4b4,
Te6edf3displayUnitsTb4b4b4: Te6edf3MeasurementSystemTb4b4b4,
Te6edf3myNodeNumTb4b4b4: Tffa657Int?Tb4b4b4,
Te6edf3selectedPositionTimeTb4b4b4: Tffa657Int? Tff7b72= Tff7b72nullTb4b4b4,
Te6edf3onPositionSelectTb4b4b4: Tb4b4b4(Tb4b4b4(Tffa657IntTb4b4b4) Tff7b72-Tff7b72> Tffa657UnitTb4b4b4)Tff7b72? Tff7b72= Tff7b72nullTb4b4b4,
Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3isHighPriority Tff7b72= Te6edf3focusedNodeTb4b4b4.Te6edf3num Tff7b72=Tff7b72= Te6edf3myNodeNum Tff7b72|Tff7b72| Te6edf3focusedNodeTb4b4b4.Te6edf3isFavorite
Tff7b72val Te6edf3activeNodeZIndex Tff7b72= Tff7b72if Tb4b4b4(Te6edf3isHighPriorityTb4b4b4) T79c0ff5f Tff7b72else T79c0ff4f
Tff7b72val Te6edf3selectedColor Tff7b72= Te6edf3MaterialThemeTb4b4b4.Te6edf3colorSchemeTb4b4b4.Te6edf3primary

Te6edf3sortedPositionsTb4b4b4.Te6edf3forEachIndexed Tb4b4b4{ Te6edf3indexTb4b4b4, Te6edf3position Tff7b72-Tff7b72>
Te6edf3keyTb4b4b4(Te6edf3positionTb4b4b4.Te6edf3timeTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3markerState Tff7b72= Te6edf3rememberUpdatedMarkerStateTb4b4b4(Te6edf3position Tff7b72= Te6edf3positionTb4b4b4.Te6edf3toLatLngTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3alpha Tff7b72=
Tff7b72if Tb4b4b4(Te6edf3sortedPositionsTb4b4b4.Te6edf3size Tff7b72> T79c0ff1Tb4b4b4) Tb4b4b4{
Te6edf3indexTb4b4b4.Te6edf3toFloatTb4b4b4(Tb4b4b4) Tff7b72/ Tb4b4b4(Te6edf3sortedPositionsTb4b4b4.Te6edf3sizeTb4b4b4.Te6edf3toFloatTb4b4b4(Tb4b4b4) Tff7b72- T79c0ff1Tb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
T79c0ff1f
Tb4b4b4}
Tff7b72val Te6edf3isSelected Tff7b72= Te6edf3positionTb4b4b4.Te6edf3time Tff7b72=Tff7b72= Te6edf3selectedPositionTime
Tff7b72val Te6edf3color Tff7b72=
Tff7b72if Tb4b4b4(Te6edf3isSelectedTb4b4b4) Tb4b4b4{
Te6edf3selectedColor
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3ColorTb4b4b4(Te6edf3focusedNodeTb4b4b4.Te6edf3colorsTb4b4b4.Te6edf3secondTb4b4b4)Tb4b4b4.Te6edf3copyTb4b4b4(Te6edf3alpha Tff7b72= Te6edf3alphaTb4b4b4)
Tb4b4b4}

Tff7b72if Tb4b4b4(Te6edf3index Tff7b72=Tff7b72= Te6edf3sortedPositionsTb4b4b4.Te6edf3lastIndexTb4b4b4) Tb4b4b4{
Te6edf3MarkerComposableTb4b4b4(
Te6edf3state Tff7b72= Te6edf3markerStateTb4b4b4,
Te6edf3zIndex Tff7b72= Te6edf3activeNodeZIndexTb4b4b4,
Te6edf3alpha Tff7b72= Tff7b72if Tb4b4b4(Te6edf3isHighPriorityTb4b4b4) T79c0ff1.0f Tff7b72else T79c0ff0.9fTb4b4b4,
Te6edf3onClick Tff7b72= Tb4b4b4{
Te6edf3onPositionSelectTff7b72?.Te6edf3invokeTb4b4b4(Te6edf3positionTb4b4b4.Te6edf3timeTb4b4b4)
Tff7b72false T8b949e// Allow default info window behavior
Tb4b4b4}Tb4b4b4,
Tb4b4b4) Tb4b4b4{
Te6edf3NodeChipTb4b4b4(Te6edf3node Tff7b72= Te6edf3focusedNodeTb4b4b4)
Tb4b4b4}
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3MarkerInfoWindowComposableTb4b4b4(
Te6edf3state Tff7b72= Te6edf3markerStateTb4b4b4,
Te6edf3title Tff7b72= Te6edf3stringResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3positionTb4b4b4)Tb4b4b4,
Te6edf3snippet Tff7b72= Te6edf3formatAgoTb4b4b4(Te6edf3positionTb4b4b4.Te6edf3timeTb4b4b4)Tb4b4b4,
Te6edf3zIndex Tff7b72= Tff7b72if Tb4b4b4(Te6edf3isSelectedTb4b4b4) Te6edf3activeNodeZIndex Tff7b72- T79c0ff0.5f Tff7b72else T79c0ff1f Tff7b72+ Te6edf3alphaTb4b4b4,
Te6edf3onClick Tff7b72= Tb4b4b4{
Te6edf3onPositionSelectTff7b72?.Te6edf3invokeTb4b4b4(Te6edf3positionTb4b4b4.Te6edf3timeTb4b4b4)
Tff7b72false T8b949e// Allow default info window behavior
Tb4b4b4}Tb4b4b4,
Te6edf3infoContent Tff7b72= Tb4b4b4{ Te6edf3PositionInfoWindowContentTb4b4b4(Te6edf3position Tff7b72= Te6edf3positionTb4b4b4, Te6edf3displayUnits Tff7b72= Te6edf3displayUnitsTb4b4b4) Tb4b4b4}Tb4b4b4,
Tb4b4b4) Tb4b4b4{
Te6edf3IconTb4b4b4(
Te6edf3imageVector Tff7b72= Te6edf3MeshtasticIconsTb4b4b4.Te6edf3TripOriginTb4b4b4,
Te6edf3contentDescription Tff7b72= Te6edf3stringResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3track_pointTb4b4b4)Tb4b4b4,
Te6edf3tint Tff7b72= Te6edf3colorTb4b4b4,
Te6edf3modifier Tff7b72= Tff7b72if Tb4b4b4(Te6edf3isSelectedTb4b4b4) Te6edf3ModifierTb4b4b4.Te6edf3sizeTb4b4b4(T79c0ff3T79c0ff2.Te6edf3dpTb4b4b4) Tff7b72else Te6edf3ModifierTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

T8b949e// Gradient polyline segments
Tff7b72if Tb4b4b4(Te6edf3sortedPositionsTb4b4b4.Te6edf3size Tff7b72> T79c0ff1Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3segments Tff7b72= Te6edf3sortedPositionsTb4b4b4.Te6edf3windowedTb4b4b4(Te6edf3size Tff7b72= T79c0ff2Tb4b4b4, Te6edf3step Tff7b72= T79c0ff1Tb4b4b4, Te6edf3partialWindows Tff7b72= Tff7b72falseTb4b4b4)
Te6edf3segmentsTb4b4b4.Te6edf3forEachIndexed Tb4b4b4{ Te6edf3indexTb4b4b4, Te6edf3segmentPoints Tff7b72-Tff7b72>
Tff7b72val Te6edf3alpha Tff7b72= Te6edf3indexTb4b4b4.Te6edf3toFloatTb4b4b4(Tb4b4b4) Tff7b72/ Tb4b4b4(Te6edf3segmentsTb4b4b4.Te6edf3sizeTb4b4b4.Te6edf3toFloatTb4b4b4(Tb4b4b4) Tff7b72- T79c0ff1Tb4b4b4)
Te6edf3PolylineTb4b4b4(
Te6edf3points Tff7b72= Te6edf3segmentPointsTb4b4b4.Te6edf3map Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3toLatLngTb4b4b4(Tb4b4b4) Tb4b4b4}Tb4b4b4,
Te6edf3jointType Tff7b72= Te6edf3JointTypeTb4b4b4.Te6edf3ROUNDTb4b4b4,
Te6edf3color Tff7b72= Te6edf3ColorTb4b4b4(Te6edf3focusedNodeTb4b4b4.Te6edf3colorsTb4b4b4.Te6edf3secondTb4b4b4)Tb4b4b4.Te6edf3copyTb4b4b4(Te6edf3alpha Tff7b72= Te6edf3alphaTb4b4b4)Tb4b4b4,
Te6edf3width Tff7b72= T79c0ff8fTb4b4b4,
Te6edf3zIndex Tff7b72= T79c0ff0.6fTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Tf0883e@Composable
Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffLongMethodTa5d6ff"Tb4b4b4)
Tff7b72private Tff7b72fun Td2a8ffPositionInfoWindowContentTb4b4b4(Te6edf3positionTb4b4b4: Te6edf3PositionTb4b4b4, Te6edf3displayUnitsTb4b4b4: Te6edf3MeasurementSystem Tff7b72= Te6edf3MeasurementSystemTb4b4b4.Te6edf3METRICTb4b4b4) Tb4b4b4{
Tf0883e@Composable
Tff7b72fun Td2a8ffPositionRowTb4b4b4(Te6edf3labelTb4b4b4: Tffa657StringTb4b4b4, Te6edf3valueTb4b4b4: Tffa657StringTb4b4b4) Tb4b4b4{
Te6edf3RowTb4b4b4(Te6edf3modifier Tff7b72= Te6edf3ModifierTb4b4b4.Te6edf3paddingTb4b4b4(Te6edf3horizontal Tff7b72= T79c0ff8.Te6edf3dpTb4b4b4)Tb4b4b4, Te6edf3verticalAlignment Tff7b72= Te6edf3AlignmentTb4b4b4.Te6edf3CenterVerticallyTb4b4b4) Tb4b4b4{
Te6edf3TextTb4b4b4(Te6edf3labelTb4b4b4, Te6edf3style Tff7b72= Te6edf3MaterialThemeTb4b4b4.Te6edf3typographyTb4b4b4.Te6edf3labelMediumTb4b4b4)
Te6edf3SpacerTb4b4b4(Te6edf3modifier Tff7b72= Te6edf3ModifierTb4b4b4.Te6edf3widthTb4b4b4(T79c0ff1T79c0ff6.Te6edf3dpTb4b4b4)Tb4b4b4)
Te6edf3TextTb4b4b4(Te6edf3valueTb4b4b4, Te6edf3style Tff7b72= Te6edf3MaterialThemeTb4b4b4.Te6edf3typographyTb4b4b4.Te6edf3labelMediumTb4b4b4)
Tb4b4b4}
Tb4b4b4}

Te6edf3Card Tb4b4b4{
Te6edf3ColumnTb4b4b4(Te6edf3modifier Tff7b72= Te6edf3ModifierTb4b4b4.Te6edf3paddingTb4b4b4(T79c0ff8.Te6edf3dpTb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3PositionRowTb4b4b4(
Te6edf3label Tff7b72= Te6edf3stringResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3latitudeTb4b4b4)Tb4b4b4,
Te6edf3value Tff7b72= Ta5d6ff"Ta5d6ff%.5fTa5d6ff"Tb4b4b4.Te6edf3formatTb4b4b4(Tb4b4b4(Te6edf3positionTb4b4b4.Te6edf3latitude_i Tff7b72?: T79c0ff0Tb4b4b4) Tff7b72* Te6edf3DEG_DTb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3PositionRowTb4b4b4(
Te6edf3label Tff7b72= Te6edf3stringResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3longitudeTb4b4b4)Tb4b4b4,
Te6edf3value Tff7b72= Ta5d6ff"Ta5d6ff%.5fTa5d6ff"Tb4b4b4.Te6edf3formatTb4b4b4(Tb4b4b4(Te6edf3positionTb4b4b4.Te6edf3longitude_i Tff7b72?: T79c0ff0Tb4b4b4) Tff7b72* Te6edf3DEG_DTb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3PositionRowTb4b4b4(Te6edf3label Tff7b72= Te6edf3stringResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3satsTb4b4b4)Tb4b4b4, Te6edf3value Tff7b72= Te6edf3positionTb4b4b4.Te6edf3sats_in_viewTb4b4b4.Te6edf3toStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3PositionRowTb4b4b4(
Te6edf3label Tff7b72= Te6edf3stringResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3altTb4b4b4)Tb4b4b4,
Te6edf3value Tff7b72= Tb4b4b4(Te6edf3positionTb4b4b4.Te6edf3altitude Tff7b72?: T79c0ff0Tb4b4b4)Tb4b4b4.Te6edf3metersInTb4b4b4(Te6edf3displayUnitsTb4b4b4)Tb4b4b4.Te6edf3toStringTb4b4b4(Te6edf3displayUnitsTb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3PositionRowTb4b4b4(Te6edf3label Tff7b72= Te6edf3stringResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3speedTb4b4b4)Tb4b4b4, Te6edf3value Tff7b72= Te6edf3speedFromPositionTb4b4b4(Te6edf3positionTb4b4b4, Te6edf3displayUnitsTb4b4b4)Tb4b4b4)
Te6edf3PositionRowTb4b4b4(
Te6edf3label Tff7b72= Te6edf3stringResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3headingTb4b4b4)Tb4b4b4,
Te6edf3value Tff7b72= Ta5d6ff"Ta5d6ff%.0f°Ta5d6ff"Tb4b4b4.Te6edf3formatTb4b4b4(Tb4b4b4(Te6edf3positionTb4b4b4.Te6edf3ground_track Tff7b72?: T79c0ff0Tb4b4b4) Tff7b72* Te6edf3HEADING_DEGTb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3PositionRowTb4b4b4(Te6edf3label Tff7b72= Te6edf3stringResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3timestampTb4b4b4)Tb4b4b4, Te6edf3value Tff7b72= Te6edf3positionTb4b4b4.Te6edf3formatPositionTimeTb4b4b4(Tb4b4b4)Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Tf0883e@Composable
Tff7b72private Tff7b72fun Td2a8ffspeedFromPositionTb4b4b4(Te6edf3positionTb4b4b4: Te6edf3PositionTb4b4b4, Te6edf3displayUnitsTb4b4b4: Te6edf3MeasurementSystemTb4b4b4)Tb4b4b4: Tffa657String Tb4b4b4{
T8b949e// Position.ground_speed is km/h on the wire (proto canon), not m/s.
Tff7b72val Te6edf3speedRes Tff7b72= Tff7b72if Tb4b4b4(Te6edf3displayUnits Tff7b72=Tff7b72= Te6edf3MeasurementSystemTb4b4b4.Te6edf3IMPERIALTb4b4b4) Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3speed_mph Tff7b72else Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3speed_kmh
Tff7b72return Te6edf3stringResourceTb4b4b4(Te6edf3speedResTb4b4b4, Tb4b4b4(Te6edf3positionTb4b4b4.Te6edf3ground_speed Tff7b72?: T79c0ff0Tb4b4b4)Tb4b4b4.Te6edf3kmhInTb4b4b4(Te6edf3displayUnitsTb4b4b4)Tb4b4b4)
Tb4b4b4}

T8b949e// endregion

T8b949e// region --- Traceroute Map Content ---

Tf0883e@OptInTb4b4b4(Te6edf3MapsComposeExperimentalApiTff7b72::Te6edf3classTb4b4b4)
Tf0883e@Composable
Tff7b72private Tff7b72fun Td2a8ffTracerouteMapContentTb4b4b4(
Te6edf3forwardOffsetPointsTb4b4b4: Te6edf3ListTff7b72<Te6edf3LatLngTff7b72>Tb4b4b4,
Te6edf3returnOffsetPointsTb4b4b4: Te6edf3ListTff7b72<Te6edf3LatLngTff7b72>Tb4b4b4,
Te6edf3forwardPointCountTb4b4b4: Tffa657IntTb4b4b4,
Te6edf3returnPointCountTb4b4b4: Tffa657IntTb4b4b4,
Te6edf3displayNodesTb4b4b4: Te6edf3ListTff7b72<Te6edf3NodeTff7b72>Tb4b4b4,
Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3forwardPointCount Tff7b72>Tff7b72= T79c0ff2Tb4b4b4) Tb4b4b4{
Te6edf3PolylineTb4b4b4(
Te6edf3points Tff7b72= Te6edf3forwardOffsetPointsTb4b4b4,
Te6edf3jointType Tff7b72= Te6edf3JointTypeTb4b4b4.Te6edf3ROUNDTb4b4b4,
Te6edf3color Tff7b72= Te6edf3TracerouteColorsTb4b4b4.Te6edf3OutgoingRouteTb4b4b4,
Te6edf3width Tff7b72= T79c0ff9fTb4b4b4,
Te6edf3zIndex Tff7b72= T79c0ff3.0fTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3returnPointCount Tff7b72>Tff7b72= T79c0ff2Tb4b4b4) Tb4b4b4{
Te6edf3PolylineTb4b4b4(
Te6edf3points Tff7b72= Te6edf3returnOffsetPointsTb4b4b4,
Te6edf3jointType Tff7b72= Te6edf3JointTypeTb4b4b4.Te6edf3ROUNDTb4b4b4,
Te6edf3color Tff7b72= Te6edf3TracerouteColorsTb4b4b4.Te6edf3ReturnRouteTb4b4b4,
Te6edf3width Tff7b72= T79c0ff7fTb4b4b4,
Te6edf3zIndex Tff7b72= T79c0ff2.5fTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Te6edf3displayNodesTb4b4b4.Te6edf3forEach Tb4b4b4{ Te6edf3node Tff7b72-Tff7b72>
T8b949e// Key by the stable node num so each marker's composition state (and MarkerComposable's cached
T8b949e// icon bitmap) stays bound to its node. Without this, reordering displayNodes between reloads
T8b949e// reuses marker slots positionally and swaps node labels/positions (#6197). The remaining keys
T8b949e// are every NodeChip input (short name, colors, ignored strike-through) so the rendered chip
T8b949e// bitmap refreshes when node metadata changes.
Te6edf3keyTb4b4b4(Te6edf3nodeTb4b4b4.Te6edf3numTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3markerState Tff7b72= Te6edf3rememberUpdatedMarkerStateTb4b4b4(Te6edf3position Tff7b72= Te6edf3nodeTb4b4b4.Te6edf3positionTb4b4b4.Te6edf3toLatLngTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3MarkerComposableTb4b4b4(
Te6edf3nodeTb4b4b4.Te6edf3numTb4b4b4,
Te6edf3nodeTb4b4b4.Te6edf3userTb4b4b4.Te6edf3short_nameTb4b4b4,
Te6edf3nodeTb4b4b4.Te6edf3colorsTb4b4b4,
Te6edf3nodeTb4b4b4.Te6edf3isIgnoredTb4b4b4,
Te6edf3state Tff7b72= Te6edf3markerStateTb4b4b4,
Te6edf3zIndex Tff7b72= T79c0ff4fTb4b4b4,
Tb4b4b4) Tb4b4b4{
Te6edf3NodeChipTb4b4b4(Te6edf3node Tff7b72= Te6edf3nodeTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Tff7b72private Tff7b72fun Td2a8ffoffsetPolylineTb4b4b4(
Te6edf3pointsTb4b4b4: Te6edf3ListTff7b72<Te6edf3LatLngTff7b72>Tb4b4b4,
Te6edf3offsetMetersTb4b4b4: Tffa657DoubleTb4b4b4,
Te6edf3headingReferencePointsTb4b4b4: Te6edf3ListTff7b72<Te6edf3LatLngTff7b72> Tff7b72= Te6edf3pointsTb4b4b4,
Te6edf3sideMultiplierTb4b4b4: Tffa657Double Tff7b72= T79c0ff1.0Tb4b4b4,
Tb4b4b4)Tb4b4b4: Te6edf3ListTff7b72<Te6edf3LatLngTff7b72> Tb4b4b4{
Tff7b72val Te6edf3headingPoints Tff7b72= Te6edf3headingReferencePointsTb4b4b4.Te6edf3takeIf Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3size Tff7b72>Tff7b72= T79c0ff2 Tb4b4b4} Tff7b72?: Te6edf3points
Tff7b72if Tb4b4b4(Te6edf3pointsTb4b4b4.Te6edf3size Tff7b72< T79c0ff2 Tff7b72|Tff7b72| Te6edf3headingPointsTb4b4b4.Te6edf3size Tff7b72< T79c0ff2 Tff7b72|Tff7b72| Te6edf3offsetMeters Tff7b72=Tff7b72= T79c0ff0.0Tb4b4b4) Tff7b72return Te6edf3points

Tff7b72val Te6edf3headings Tff7b72=
Te6edf3headingPointsTb4b4b4.Te6edf3mapIndexed Tb4b4b4{ Te6edf3indexTb4b4b4, Te6edf3_ Tff7b72-Tff7b72>
Tff7b72when Tb4b4b4(Te6edf3indexTb4b4b4) Tb4b4b4{
T79c0ff0 Tff7b72-Tff7b72> Te6edf3SphericalUtilTb4b4b4.Te6edf3computeHeadingTb4b4b4(Te6edf3headingPointsTff7b72[T79c0ff0Tff7b72]Tb4b4b4, Te6edf3headingPointsTff7b72[T79c0ff1Tff7b72]Tb4b4b4)

Te6edf3headingPointsTb4b4b4.Te6edf3lastIndex Tff7b72-Tff7b72>
Te6edf3SphericalUtilTb4b4b4.Te6edf3computeHeadingTb4b4b4(
Te6edf3headingPointsTff7b72[Te6edf3headingPointsTb4b4b4.Te6edf3lastIndex Tff7b72- T79c0ff1Tff7b72]Tb4b4b4,
Te6edf3headingPointsTff7b72[Te6edf3headingPointsTb4b4b4.Te6edf3lastIndexTff7b72]Tb4b4b4,
Tb4b4b4)

Tff7b72else Tff7b72-Tff7b72> Te6edf3SphericalUtilTb4b4b4.Te6edf3computeHeadingTb4b4b4(Te6edf3headingPointsTff7b72[Te6edf3index Tff7b72- T79c0ff1Tff7b72]Tb4b4b4, Te6edf3headingPointsTff7b72[Te6edf3index Tff7b72+ T79c0ff1Tff7b72]Tb4b4b4)
Tb4b4b4}
Tb4b4b4}

Tff7b72return Te6edf3pointsTb4b4b4.Te6edf3mapIndexed Tb4b4b4{ Te6edf3indexTb4b4b4, Te6edf3point Tff7b72-Tff7b72>
Tff7b72val Te6edf3heading Tff7b72= Te6edf3headingsTff7b72[Te6edf3indexTb4b4b4.Te6edf3coerceInTb4b4b4(T79c0ff0Tb4b4b4, Te6edf3headingsTb4b4b4.Te6edf3lastIndexTb4b4b4)Tff7b72]
Tff7b72val Te6edf3perpendicularHeading Tff7b72= Te6edf3heading Tff7b72+ Tb4b4b4(T79c0ff9T79c0ff0.0 Tff7b72* Te6edf3sideMultiplierTb4b4b4)
Te6edf3SphericalUtilTb4b4b4.Te6edf3computeOffsetTb4b4b4(Te6edf3pointTb4b4b4, Te6edf3absTb4b4b4(Te6edf3offsetMetersTb4b4b4)Tb4b4b4, Te6edf3perpendicularHeadingTb4b4b4)
Tb4b4b4}
Tb4b4b4}

T8b949e// endregion

T8b949e// region --- Map Layers ---

Tf0883e@OptInTb4b4b4(Te6edf3MapsComposeExperimentalApiTff7b72::Te6edf3classTb4b4b4)
Tf0883e@Composable
Tff7b72private Tff7b72fun Td2a8ffMapLayerOverlayTb4b4b4(Te6edf3layerItemTb4b4b4: Te6edf3MapLayerItemTb4b4b4, Te6edf3opacityTb4b4b4: Tffa657FloatTb4b4b4, Te6edf3mapViewModelTb4b4b4: Te6edf3MapViewModelTb4b4b4) Tb4b4b4{
Tff7b72var Te6edf3currentLayer Tff7b72by Te6edf3remember Tb4b4b4{ Te6edf3mutableStateOfTff7b72<Te6edf3RenderedMapLayer?Tff7b72>Tb4b4b4(Tff7b72nullTb4b4b4) Tb4b4b4}

T8b949e// Opacity is part of the key: maps-utils has no way to restyle a layer already on the map, so a fade is a
T8b949e// teardown and a redraw.
Te6edf3MapEffectTb4b4b4(Te6edf3layerItemTb4b4b4.Te6edf3idTb4b4b4, Te6edf3layerItemTb4b4b4.Te6edf3refreshTokenTb4b4b4, Te6edf3opacityTb4b4b4) Tb4b4b4{ Te6edf3map Tff7b72-Tff7b72>
Te6edf3currentLayerTff7b72?.Te6edf3safeHideTb4b4b4(Tb4b4b4)
Te6edf3currentLayer Tff7b72= Tff7b72null
Tff7b72val Te6edf3bytes Tff7b72= Te6edf3mapViewModelTb4b4b4.Te6edf3readLayerBytesTb4b4b4(Te6edf3layerItemTb4b4b4) Tff7b72?: Tff7b72returnTf0883e@MapEffect
Tff7b72val Te6edf3layer Tff7b72=
Tff7b72try Tb4b4b4{
Tff7b72val Te6edf3dataLayer Tff7b72=
Te6edf3withContextTb4b4b4(Te6edf3DispatchersTb4b4b4.Te6edf3IOTb4b4b4) Tb4b4b4{
T8b949e// Buffered because the KMZ sniff marks and resets the stream before the parser reads it.
Te6edf3BufferedInputStreamTb4b4b4(Te6edf3ByteArrayInputStreamTb4b4b4(Te6edf3bytesTb4b4b4)Tb4b4b4)Tb4b4b4.Te6edf3use Tb4b4b4{ Te6edf3stream Tff7b72-Tff7b72>
Te6edf3parseMapLayerTb4b4b4(Te6edf3layerItemTb4b4b4.Te6edf3layerTypeTb4b4b4, Te6edf3streamTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3dataLayer Tff7b72=Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3withTagTb4b4b4(Ta5d6ff"Ta5d6ffMapViewTa5d6ff"Tb4b4b4)Tb4b4b4.Te6edf3e Tb4b4b4{ Ta5d6ff"Ta5d6ffError loading map layer: Tffd700${Te6edf3layerItemTb4b4b4.Te6edf3nameTffd700}Ta5d6ff (unrecognized format)Ta5d6ff" Tb4b4b4}
Tff7b72null
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3RenderedMapLayerTb4b4b4(Te6edf3mapTb4b4b4, Te6edf3dataLayerTb4b4b4.Te6edf3scaledByOpacityTb4b4b4(Te6edf3opacityTb4b4b4)Tb4b4b4, Te6edf3opacityTb4b4b4)
Tb4b4b4}
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3CancellationExceptionTb4b4b4) Tb4b4b4{
T8b949e// Not a load failure: this MapEffect is relaunched on every refresh (refreshToken) and cancelled when
T8b949e// the layer or the map leaves the composition, which lands here while parseMapLayer is suspended.
T8b949e// Swallowing it broke structured concurrency and reported routine refreshes to error tracking.
Tff7b72throw Te6edf3e
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3ExceptionTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3withTagTb4b4b4(Ta5d6ff"Ta5d6ffMapViewTa5d6ff"Tb4b4b4)Tb4b4b4.Te6edf3eTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ffError loading map layer: Tffd700${Te6edf3layerItemTb4b4b4.Te6edf3nameTffd700}Ta5d6ff" Tb4b4b4}
Tff7b72null
Tb4b4b4}
Te6edf3layerTff7b72?.Te6edf3let Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3layerItemTb4b4b4.Te6edf3isVisibleTb4b4b4) Tffa657itTb4b4b4.Te6edf3safeShowTb4b4b4(Tb4b4b4)
Te6edf3currentLayer Tff7b72= Tffa657it
Tb4b4b4}
Tb4b4b4}

Te6edf3DisposableEffectTb4b4b4(Te6edf3layerItemTb4b4b4.Te6edf3idTb4b4b4) Tb4b4b4{
Te6edf3onDispose Tb4b4b4{
Te6edf3currentLayerTff7b72?.Te6edf3safeHideTb4b4b4(Tb4b4b4)
Te6edf3currentLayer Tff7b72= Tff7b72null
Tb4b4b4}
Tb4b4b4}

Te6edf3LaunchedEffectTb4b4b4(Te6edf3layerItemTb4b4b4.Te6edf3isVisibleTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3layer Tff7b72= Te6edf3currentLayer Tff7b72?: Tff7b72returnTf0883e@LaunchedEffect
Tff7b72if Tb4b4b4(Te6edf3layerItemTb4b4b4.Te6edf3isVisibleTb4b4b4) Te6edf3layerTb4b4b4.Te6edf3safeShowTb4b4b4(Tb4b4b4) Tff7b72else Te6edf3layerTb4b4b4.Te6edf3safeHideTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4}

T8b949e/**
* Parse a custom overlay into the maps-utils platform-agnostic [DataLayer] model; null if the format is unrecognized.
*/
Tff7b72private Tff7b72fun Td2a8ffparseMapLayerTb4b4b4(Te6edf3layerTypeTb4b4b4: Te6edf3LayerTypeTb4b4b4, Te6edf3streamTb4b4b4: Te6edf3InputStreamTb4b4b4)Tb4b4b4: Te6edf3DataLayer? Tff7b72= Tff7b72when Tb4b4b4(Te6edf3layerTypeTb4b4b4) Tb4b4b4{
T8b949e// Converted with the app's own reader rather than maps-utils': keeping both parsers meant keeping the
T8b949e// maps-utils/xmlutil pairing that made every KML import die with NoSuchMethodError in 2.8.0–2.8.1, held off
T8b949e// only by a version floor and a canary test.
Te6edf3LayerTypeTb4b4b4.Te6edf3KML Tff7b72-Tff7b72>
Te6edf3convertKmlSourceTb4b4b4(Te6edf3BufferedInputStreamTb4b4b4(Te6edf3streamTb4b4b4)Tb4b4b4)Tff7b72?.Te6edf3let Tb4b4b4{ Te6edf3imported Tff7b72-Tff7b72>
Te6edf3GeoJsonParserTb4b4b4(Tb4b4b4)
Tb4b4b4.Te6edf3parseTb4b4b4(Te6edf3importedTb4b4b4.Te6edf3geoJsonTb4b4b4.Te6edf3byteInputStreamTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72?.Te6edf3toLayerTb4b4b4(Tb4b4b4)
Tff7b72?.Te6edf3applySimpleStyleSpecTb4b4b4(Tb4b4b4)
T8b949e// A KMZ carries its icons inside the archive, and a placemark names them by their path in it. The
T8b949e// renderer resolves those through its image cache, which is seeded from this property. Ground
T8b949e// overlays ride the same bag: DataLayer is the one thing that reaches RenderedMapLayer.
Tff7b72?.Te6edf3let Tb4b4b4{ Te6edf3layer Tff7b72-Tff7b72>
Te6edf3layerTb4b4b4.Te6edf3copyTb4b4b4(
Te6edf3properties Tff7b72=
Te6edf3layerTb4b4b4.Te6edf3properties Tff7b72+
Tb4b4b4(Ta5d6ff"Ta5d6ffimagesTa5d6ff" Te6edf3to Te6edf3importedTb4b4b4.Te6edf3imagesTb4b4b4) Tff7b72+
Tb4b4b4(Ta5d6ff"Ta5d6ffgroundOverlaysTa5d6ff" Te6edf3to Te6edf3importedTb4b4b4.Te6edf3groundOverlaysTb4b4b4)Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}

Te6edf3LayerTypeTb4b4b4.Te6edf3GEOJSONTb4b4b4,
Te6edf3LayerTypeTb4b4b4.Te6edf3COVERAGETb4b4b4,
Tff7b72-Tff7b72> Te6edf3GeoJsonParserTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3parseTb4b4b4(Te6edf3streamTb4b4b4)Tff7b72?.Te6edf3toLayerTb4b4b4(Tb4b4b4)Tff7b72?.Te6edf3applySimpleStyleSpecTb4b4b4(Tb4b4b4)
Tb4b4b4}

T8b949e/**
* A parsed custom overlay (KML/KMZ/GeoJSON) plus the machinery to draw it on the map.
*
* Each [show] creates a fresh single-use [MapViewRenderer] and [hide] tears it down with [MapViewRenderer.clear].
* Renderers are deliberately not reused: clear() cancels their icon-loading scope for good, and per-feature removal
* ([MapViewRenderer.removeFeature]) silently no-ops for MultiGeometry features (the renderer keys rendered map objects
* by internal per-geometry copies), so clear() is the only teardown that reliably takes everything off the map.
*/
Tff7b72private Tff7b72class T56d364RenderedMapLayerTb4b4b4(
Tff7b72private Tff7b72val Te6edf3mapTb4b4b4: Te6edf3GmsGoogleMapTb4b4b4,
Tff7b72private Tff7b72val Te6edf3dataLayerTb4b4b4: Te6edf3DataLayerTb4b4b4,
Tff7b72private Tff7b72val Te6edf3opacityTb4b4b4: Tffa657FloatTb4b4b4,
Tb4b4b4) Tb4b4b4{
Tff7b72private Tff7b72var Te6edf3rendererTb4b4b4: Te6edf3MapViewRenderer? Tff7b72= Tff7b72null

T8b949e/** Images extracted from a KMZ archive, keyed by archive path; the KML mapper stashes them in layer properties. */
Tff7b72private Tff7b72val Te6edf3localImagesTb4b4b4: Te6edf3MapTff7b72<Tffa657StringTb4b4b4, Te6edf3BitmapTff7b72>
Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffUNCHECKED_CASTTa5d6ff"Tb4b4b4)
Tff7b72getTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3dataLayerTb4b4b4.Te6edf3propertiesTff7b72[Ta5d6ff"Ta5d6ffimagesTa5d6ff"Tff7b72] Tff7b72as? Te6edf3MapTff7b72<Tffa657StringTb4b4b4, Te6edf3BitmapTff7b72> Tff7b72?: Te6edf3emptyMapTb4b4b4(Tb4b4b4)

T8b949e/** KML ground overlays, riding the same property bag as the images they draw with. */
Tff7b72private Tff7b72val Te6edf3groundOverlaysTb4b4b4: Te6edf3ListTff7b72<Te6edf3KmlGroundOverlayTff7b72>
Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffUNCHECKED_CASTTa5d6ff"Tb4b4b4)
Tff7b72getTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3dataLayerTb4b4b4.Te6edf3propertiesTff7b72[Ta5d6ff"Ta5d6ffgroundOverlaysTa5d6ff"Tff7b72] Tff7b72as? Te6edf3ListTff7b72<Te6edf3KmlGroundOverlayTff7b72> Tff7b72?: Te6edf3emptyListTb4b4b4(Tb4b4b4)

Tff7b72private Tff7b72val Te6edf3renderedGroundOverlays Tff7b72= Te6edf3mutableListOfTff7b72<Te6edf3GroundOverlayTff7b72>Tb4b4b4(Tb4b4b4)

Tff7b72fun Td2a8ffshowTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3renderer Tff7b72!Tff7b72= Tff7b72nullTb4b4b4) Tff7b72return
Te6edf3renderer Tff7b72=
Te6edf3MapViewRendererTb4b4b4(Te6edf3mapTb4b4b4, Te6edf3UrlIconProviderTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4.Te6edf3also Tb4b4b4{ Te6edf3r Tff7b72-Tff7b72>
Te6edf3localImagesTb4b4b4.Te6edf3forEach Tb4b4b4{ Tb4b4b4(Te6edf3pathTb4b4b4, Te6edf3bitmapTb4b4b4) Tff7b72-Tff7b72> Te6edf3rTb4b4b4.Te6edf3cacheImageDataTb4b4b4(Te6edf3pathTb4b4b4, Te6edf3bitmapTb4b4b4) Tb4b4b4}
Te6edf3rTb4b4b4.Te6edf3addLayerTb4b4b4(Te6edf3dataLayerTb4b4b4)
Tb4b4b4}
Te6edf3groundOverlaysTb4b4b4.Te6edf3forEach Tb4b4b4{ Te6edf3overlay Tff7b72-Tff7b72>
Tff7b72val Te6edf3image Tff7b72= Te6edf3localImagesTff7b72[Te6edf3overlayTb4b4b4.Te6edf3hrefTff7b72]
Tff7b72if Tb4b4b4(Te6edf3image Tff7b72=Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
T8b949e// The Site Planner's KML export names a sibling file that was never in an archive; there is
T8b949e// nothing to drape. Count, not href — the image name is user content.
Te6edf3LoggerTb4b4b4.Te6edf3withTagTb4b4b4(Ta5d6ff"Ta5d6ffMapViewTa5d6ff"Tb4b4b4)Tb4b4b4.Te6edf3w Tb4b4b4{ Ta5d6ff"Ta5d6ffSkipping a ground overlay whose image is not packed in the archiveTa5d6ff" Tb4b4b4}
Tff7b72returnTf0883e@forEach
Tb4b4b4}
Te6edf3mapTb4b4b4.Te6edf3addGroundOverlayTb4b4b4(
Te6edf3GroundOverlayOptionsTb4b4b4(Tb4b4b4)
Tb4b4b4.Te6edf3positionFromBoundsTb4b4b4(
Te6edf3LatLngBoundsTb4b4b4(Te6edf3LatLngTb4b4b4(Te6edf3overlayTb4b4b4.Te6edf3southTb4b4b4, Te6edf3overlayTb4b4b4.Te6edf3westTb4b4b4)Tb4b4b4, Te6edf3LatLngTb4b4b4(Te6edf3overlayTb4b4b4.Te6edf3northTb4b4b4, Te6edf3overlayTb4b4b4.Te6edf3eastTb4b4b4)Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tb4b4b4.Te6edf3imageTb4b4b4(Te6edf3BitmapDescriptorFactoryTb4b4b4.Te6edf3fromBitmapTb4b4b4(Te6edf3imageTb4b4b4)Tb4b4b4)
T8b949e// KML's rotation is degrees counter-clockwise about the box centre; bearing is clockwise.
Tb4b4b4.Te6edf3bearingTb4b4b4(Tb4b4b4(Tff7b72-Te6edf3overlayTb4b4b4.Te6edf3rotationDegreesTb4b4b4)Tb4b4b4.Te6edf3toFloatTb4b4b4(Tb4b4b4)Tb4b4b4)
T8b949e// A draped image is a raster, so unlike the vector features it does have a transparency to set.
Tb4b4b4.Te6edf3transparencyTb4b4b4(Tb4b4b4(T79c0ff1f Tff7b72- Te6edf3opacityTb4b4b4)Tb4b4b4.Te6edf3coerceInTb4b4b4(T79c0ff0fTb4b4b4, T79c0ff1fTb4b4b4)Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72?.Te6edf3let Tb4b4b4{ Te6edf3renderedGroundOverlays Tff7b72+Tff7b72= Tffa657it Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Tff7b72fun Td2a8ffhideTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3rendererTff7b72?.Te6edf3clearTb4b4b4(Tb4b4b4)
Te6edf3renderer Tff7b72= Tff7b72null
Te6edf3renderedGroundOverlaysTb4b4b4.Te6edf3forEach Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3removeTb4b4b4(Tb4b4b4) Tb4b4b4}
Te6edf3renderedGroundOverlaysTb4b4b4.Te6edf3clearTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4}

Tff7b72private Tff7b72fun Te6edf3RenderedMapLayerTb4b4b4.Td2a8ffsafeShowTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72try Tb4b4b4{
Te6edf3showTb4b4b4(Tb4b4b4)
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3ExceptionTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3withTagTb4b4b4(Ta5d6ff"Ta5d6ffMapViewTa5d6ff"Tb4b4b4)Tb4b4b4.Te6edf3eTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ffError adding map layerTa5d6ff" Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Tff7b72private Tff7b72fun Te6edf3RenderedMapLayerTb4b4b4.Td2a8ffsafeHideTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72try Tb4b4b4{
Te6edf3hideTb4b4b4(Tb4b4b4)
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3ExceptionTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3withTagTb4b4b4(Ta5d6ff"Ta5d6ffMapViewTa5d6ff"Tb4b4b4)Tb4b4b4.Te6edf3eTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ffError removing map layerTa5d6ff" Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

T8b949e/**
* Apply simplestyle-spec (https://github.com/mapbox/simplestyle-spec) properties to a parsed GeoJSON layer.
*
* The maps-utils GeoJSON mapper reads `fill`/`stroke`/`stroke-width`/`fill-opacity`/`stroke-opacity` itself, but misses
* several things this app relies on for Meshtastic Site Planner coverage exports: the legacy `color` fallback,
* `rgb()`/`rgba()` colors, a default fill opacity so stacked contour bands read as a gradient, and polygon styling for
* MultiPolygon features (the mapper styles any multi-geometry as a line). Rebuild each feature's style from its
* properties so the coverage draws in its dBm colors instead of the default black outline.
*/
Tff7b72internal Tff7b72fun Te6edf3DataLayerTb4b4b4.Td2a8ffapplySimpleStyleSpecTb4b4b4(Tb4b4b4)Tb4b4b4: Te6edf3DataLayer Tff7b72= Te6edf3copyTb4b4b4(Te6edf3features Tff7b72= Te6edf3featuresTb4b4b4.Te6edf3map Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3applySimpleStyleSpecTb4b4b4(Tb4b4b4) Tb4b4b4}Tb4b4b4)

Tff7b72internal Tff7b72fun Te6edf3FeatureTb4b4b4.Td2a8ffapplySimpleStyleSpecTb4b4b4(Tb4b4b4)Tb4b4b4: Te6edf3Feature Tb4b4b4{
Tff7b72val Te6edf3fill Tff7b72= Te6edf3cssColorTb4b4b4(Ta5d6ff"Ta5d6fffillTa5d6ff"Tb4b4b4) Tff7b72?: Te6edf3cssColorTb4b4b4(Ta5d6ff"Ta5d6ffcolorTa5d6ff"Tb4b4b4)
Tff7b72val Te6edf3fillOpacity Tff7b72= Te6edf3stringPropertyTb4b4b4(Ta5d6ff"Ta5d6fffill-opacityTa5d6ff"Tb4b4b4)Tff7b72?.Te6edf3toFloatOrNullTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3strokeOpacity Tff7b72= Te6edf3stringPropertyTb4b4b4(Ta5d6ff"Ta5d6ffstroke-opacityTa5d6ff"Tb4b4b4)Tff7b72?.Te6edf3toFloatOrNullTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3stroke Tff7b72=
Tb4b4b4(Te6edf3cssColorTb4b4b4(Ta5d6ff"Ta5d6ffstrokeTa5d6ff"Tb4b4b4) Tff7b72?: Te6edf3cssColorTb4b4b4(Ta5d6ff"Ta5d6ffcolorTa5d6ff"Tb4b4b4)Tb4b4b4)Tff7b72?.Te6edf3let Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3strokeOpacity Tff7b72!Tff7b72= Tff7b72nullTb4b4b4) Tffa657itTb4b4b4.Te6edf3withAlphaTb4b4b4(Te6edf3strokeOpacityTb4b4b4) Tff7b72else Tffa657it
Tb4b4b4}
Tff7b72val Te6edf3strokeWidth Tff7b72= Te6edf3stringPropertyTb4b4b4(Ta5d6ff"Ta5d6ffstroke-widthTa5d6ff"Tb4b4b4)Tff7b72?.Te6edf3toFloatOrNullTb4b4b4(Tb4b4b4) Tff7b72?: Te6edf3DEFAULT_GEOJSON_STROKE_WIDTH
Tff7b72return Tff7b72when Tb4b4b4{
Te6edf3geometryTb4b4b4.Te6edf3isPolygonalTb4b4b4(Tb4b4b4) Tff7b72-Tff7b72>
Te6edf3copyTb4b4b4(
Te6edf3style Tff7b72=
Te6edf3PolygonStyleTb4b4b4(
Te6edf3fillColor Tff7b72= Te6edf3fillTff7b72?.Te6edf3resolveFillAlphaTb4b4b4(Te6edf3fillOpacityTb4b4b4) Tff7b72?: Te6edf3AndroidColorTb4b4b4.Te6edf3TRANSPARENTTb4b4b4,
Te6edf3strokeColor Tff7b72= Te6edf3stroke Tff7b72?: Te6edf3AndroidColorTb4b4b4.Te6edf3BLACKTb4b4b4,
Te6edf3strokeWidth Tff7b72= Te6edf3strokeWidthTb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)

Te6edf3geometryTb4b4b4.Te6edf3isLinearTb4b4b4(Tb4b4b4) Tff7b72-Tff7b72> Te6edf3copyTb4b4b4(Te6edf3style Tff7b72= Te6edf3LineStyleTb4b4b4(Te6edf3color Tff7b72= Te6edf3stroke Tff7b72?: Te6edf3AndroidColorTb4b4b4.Te6edf3BLACKTb4b4b4, Te6edf3width Tff7b72= Te6edf3strokeWidthTb4b4b4)Tb4b4b4)

T8b949e// A KML icon reaches us as the `icon-url` the converter writes; maps-utils' GeoJSON mapper reads no icon
T8b949e// property at all, so without this the Google map would silently lose the icons it has always drawn.
Te6edf3geometryTb4b4b4.Te6edf3isPointLikeTb4b4b4(Tb4b4b4) Tff7b72-Tff7b72>
Te6edf3stringPropertyTb4b4b4(Te6edf3ICON_URL_PROPERTYTb4b4b4)Tff7b72?.Te6edf3letTb4b4b4(Tff7b72::Te6edf3sanitizeImportedIconUrlTb4b4b4)Tff7b72?.Te6edf3let Tb4b4b4{
Te6edf3copyTb4b4b4(Te6edf3style Tff7b72= Te6edf3PointStyleTb4b4b4(Te6edf3iconUrl Tff7b72= Tffa657itTb4b4b4)Tb4b4b4)
Tb4b4b4} Tff7b72?: Tff7b72this

Tff7b72else Tff7b72-Tff7b72> Tff7b72this T8b949e// Mixed geometry collections keep the mapper's style.
Tb4b4b4}
Tb4b4b4}

T8b949e/**
* The same layer with every feature's alpha scaled by [opacity].
*
* maps-utils draws an imported layer as ordinary map objects — polygons, polylines, markers — so unlike a tile overlay
* there is nothing layer-wide to fade. Scaling rather than replacing the alpha keeps an import's own relative
* transparency: a coverage export whose contour bands are already translucent stays a gradient as the layer fades.
*
* Points included: [PointStyle] carries an ARGB colour the renderer turns into marker alpha, so a point-only layer
* would otherwise stay fully visible at 0%.
*/
Tff7b72internal Tff7b72fun Te6edf3DataLayerTb4b4b4.Td2a8ffscaledByOpacityTb4b4b4(Te6edf3opacityTb4b4b4: Tffa657FloatTb4b4b4)Tb4b4b4: Te6edf3DataLayer Tff7b72=
Tff7b72if Tb4b4b4(Te6edf3opacity Tff7b72>Tff7b72= T79c0ff1fTb4b4b4) Tff7b72this Tff7b72else Te6edf3copyTb4b4b4(Te6edf3features Tff7b72= Te6edf3featuresTb4b4b4.Te6edf3map Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3scaledByOpacityTb4b4b4(Te6edf3opacityTb4b4b4) Tb4b4b4}Tb4b4b4)

Tff7b72private Tff7b72fun Te6edf3FeatureTb4b4b4.Td2a8ffscaledByOpacityTb4b4b4(Te6edf3opacityTb4b4b4: Tffa657FloatTb4b4b4)Tb4b4b4: Te6edf3Feature Tff7b72= Tff7b72when Tb4b4b4(Tff7b72val Te6edf3featureStyle Tff7b72= Te6edf3styleTb4b4b4) Tb4b4b4{
Tff7b72is Te6edf3PolygonStyle Tff7b72-Tff7b72>
Te6edf3copyTb4b4b4(
Te6edf3style Tff7b72=
Te6edf3featureStyleTb4b4b4.Te6edf3copyTb4b4b4(
Te6edf3fillColor Tff7b72= Te6edf3featureStyleTb4b4b4.Te6edf3fillColorTb4b4b4.Te6edf3scaleAlphaTb4b4b4(Te6edf3opacityTb4b4b4)Tb4b4b4,
Te6edf3strokeColor Tff7b72= Te6edf3featureStyleTb4b4b4.Te6edf3strokeColorTb4b4b4.Te6edf3scaleAlphaTb4b4b4(Te6edf3opacityTb4b4b4)Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)

Tff7b72is Te6edf3LineStyle Tff7b72-Tff7b72> Te6edf3copyTb4b4b4(Te6edf3style Tff7b72= Te6edf3featureStyleTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3color Tff7b72= Te6edf3featureStyleTb4b4b4.Te6edf3colorTb4b4b4.Te6edf3scaleAlphaTb4b4b4(Te6edf3opacityTb4b4b4)Tb4b4b4)Tb4b4b4)

Tff7b72is Te6edf3PointStyle Tff7b72-Tff7b72> Te6edf3copyTb4b4b4(Te6edf3style Tff7b72= Te6edf3featureStyleTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3color Tff7b72= Te6edf3featureStyleTb4b4b4.Te6edf3colorTb4b4b4.Te6edf3scaleAlphaTb4b4b4(Te6edf3opacityTb4b4b4)Tb4b4b4)Tb4b4b4)

Tff7b72else Tff7b72-Tff7b72> Tff7b72this
Tb4b4b4}

Tff7b72private Tff7b72fun Te6edf3IntTb4b4b4.Td2a8ffscaleAlphaTb4b4b4(Te6edf3opacityTb4b4b4: Tffa657FloatTb4b4b4)Tb4b4b4: Tffa657Int Tff7b72= Te6edf3AndroidColorTb4b4b4.Te6edf3argbTb4b4b4(
Tb4b4b4(Te6edf3AndroidColorTb4b4b4.Te6edf3alphaTb4b4b4(Tff7b72thisTb4b4b4) Tff7b72* Te6edf3opacityTb4b4b4.Te6edf3coerceInTb4b4b4(T79c0ff0fTb4b4b4, T79c0ff1fTb4b4b4)Tb4b4b4)Tb4b4b4.Te6edf3roundToIntTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3AndroidColorTb4b4b4.Te6edf3redTb4b4b4(Tff7b72thisTb4b4b4)Tb4b4b4,
Te6edf3AndroidColorTb4b4b4.Te6edf3greenTb4b4b4(Tff7b72thisTb4b4b4)Tb4b4b4,
Te6edf3AndroidColorTb4b4b4.Te6edf3blueTb4b4b4(Tff7b72thisTb4b4b4)Tb4b4b4,
Tb4b4b4)

T8b949e/** Point or MultiPoint (a multi-geometry whose members are all points). */
Tff7b72private Tff7b72fun Te6edf3GeometryTb4b4b4.Td2a8ffisPointLikeTb4b4b4(Tb4b4b4)Tb4b4b4: Tffa657Boolean Tff7b72= Tff7b72this Tff7b72is Te6edf3PointGeometry Tff7b72|Tff7b72|
Tb4b4b4(Tff7b72this Tff7b72is Te6edf3MultiGeometry Tff7b72&Tff7b72& Te6edf3geometriesTb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4) Tff7b72&Tff7b72& Te6edf3geometriesTb4b4b4.Te6edf3all Tb4b4b4{ Tffa657it Tff7b72is Te6edf3PointGeometry Tb4b4b4}Tb4b4b4)

T8b949e/** Polygon or MultiPolygon (a multi-geometry whose members are all polygons). */
Tff7b72private Tff7b72fun Te6edf3GeometryTb4b4b4.Td2a8ffisPolygonalTb4b4b4(Tb4b4b4)Tb4b4b4: Tffa657Boolean Tff7b72=
Tff7b72this Tff7b72is Te6edf3ModelPolygon Tff7b72|Tff7b72| Tb4b4b4(Tff7b72this Tff7b72is Te6edf3MultiGeometry Tff7b72&Tff7b72& Te6edf3geometriesTb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4) Tff7b72&Tff7b72& Te6edf3geometriesTb4b4b4.Te6edf3all Tb4b4b4{ Tffa657it Tff7b72is Te6edf3ModelPolygon Tb4b4b4}Tb4b4b4)

T8b949e/** LineString or MultiLineString (a multi-geometry whose members are all line strings). */
Tff7b72private Tff7b72fun Te6edf3GeometryTb4b4b4.Td2a8ffisLinearTb4b4b4(Tb4b4b4)Tb4b4b4: Tffa657Boolean Tff7b72=
Tff7b72this Tff7b72is Te6edf3LineString Tff7b72|Tff7b72| Tb4b4b4(Tff7b72this Tff7b72is Te6edf3MultiGeometry Tff7b72&Tff7b72& Te6edf3geometriesTb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4) Tff7b72&Tff7b72& Te6edf3geometriesTb4b4b4.Te6edf3all Tb4b4b4{ Tffa657it Tff7b72is Te6edf3LineString Tb4b4b4}Tb4b4b4)

Tff7b72private Tff7b72fun Te6edf3FeatureTb4b4b4.Td2a8ffstringPropertyTb4b4b4(Te6edf3keyTb4b4b4: Tffa657StringTb4b4b4)Tb4b4b4: Tffa657String? Tff7b72= Te6edf3propertiesTff7b72[Te6edf3keyTff7b72] Tff7b72as? Tffa657String

Tff7b72private Tff7b72fun Te6edf3FeatureTb4b4b4.Td2a8ffcssColorTb4b4b4(Te6edf3keyTb4b4b4: Tffa657StringTb4b4b4)Tb4b4b4: Tffa657Int? Tff7b72= Te6edf3stringPropertyTb4b4b4(Te6edf3keyTb4b4b4)Tff7b72?.Te6edf3let Tb4b4b4{ Te6edf3parseCssColorTb4b4b4(Tffa657itTb4b4b4) Tb4b4b4}

T8b949e/**
* Resolve a polygon fill's alpha: `fill-opacity` wins when present; otherwise keep any alpha the color already carries
* (`rgba()`/`#AARRGGBB`), falling back to [DEFAULT_GEOJSON_FILL_OPACITY] for opaque fills.
*/
Tff7b72private Tff7b72fun Te6edf3IntTb4b4b4.Td2a8ffresolveFillAlphaTb4b4b4(Te6edf3fillOpacityTb4b4b4: Tffa657Float?Tb4b4b4)Tb4b4b4: Tffa657Int Tff7b72= Tff7b72when Tb4b4b4{
Te6edf3fillOpacity Tff7b72!Tff7b72= Tff7b72null Tff7b72-Tff7b72> Te6edf3withAlphaTb4b4b4(Te6edf3fillOpacityTb4b4b4)
Te6edf3AndroidColorTb4b4b4.Te6edf3alphaTb4b4b4(Tff7b72thisTb4b4b4) Tff7b72< T79c0ff2T79c0ff5T79c0ff5 Tff7b72-Tff7b72> Tff7b72this
Tff7b72else Tff7b72-Tff7b72> Te6edf3withAlphaTb4b4b4(Te6edf3DEFAULT_GEOJSON_FILL_OPACITYTb4b4b4)
Tb4b4b4}

T8b949e/** Parse a hex (`#RRGGBB`/`#AARRGGBB`), `rgb()/rgba()`, or named color to an ARGB int; null if invalid. */
Tff7b72private Tff7b72fun Td2a8ffparseCssColorTb4b4b4(Te6edf3rawTb4b4b4: Tffa657StringTb4b4b4)Tb4b4b4: Tffa657Int? Tb4b4b4{
Tff7b72val Te6edf3value Tff7b72= Te6edf3rawTb4b4b4.Te6edf3trimTb4b4b4(Tb4b4b4)
Tff7b72return Tff7b72try Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3valueTb4b4b4.Te6edf3startsWithTb4b4b4(Ta5d6ff"Ta5d6ffrgbTa5d6ff"Tb4b4b4, Te6edf3ignoreCase Tff7b72= Tff7b72trueTb4b4b4)Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3parts Tff7b72= Te6edf3valueTb4b4b4.Te6edf3substringAfterTb4b4b4(Ta5d6ff'('Tb4b4b4)Tb4b4b4.Te6edf3substringBeforeTb4b4b4(Ta5d6ff')'Tb4b4b4)Tb4b4b4.Te6edf3splitTb4b4b4(Ta5d6ff','Tb4b4b4)Tb4b4b4.Te6edf3map Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3trimTb4b4b4(Tb4b4b4) Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3partsTb4b4b4.Te6edf3size Tff7b72< T79c0ff3Tb4b4b4) Tff7b72return Tff7b72null
Tff7b72val Te6edf3alpha Tff7b72= Tff7b72if Tb4b4b4(Te6edf3partsTb4b4b4.Te6edf3size Tff7b72>Tff7b72= T79c0ff4Tb4b4b4) Tb4b4b4(Te6edf3partsTff7b72[T79c0ff3Tff7b72]Tb4b4b4.Te6edf3toFloatTb4b4b4(Tb4b4b4) Tff7b72* T79c0ff2T79c0ff5T79c0ff5fTb4b4b4)Tb4b4b4.Te6edf3roundToIntTb4b4b4(Tb4b4b4) Tff7b72else T79c0ff2T79c0ff5T79c0ff5
Te6edf3AndroidColorTb4b4b4.Te6edf3argbTb4b4b4(Te6edf3alphaTb4b4b4, Te6edf3partsTff7b72[T79c0ff0Tff7b72]Tb4b4b4.Te6edf3toIntTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3partsTff7b72[T79c0ff1Tff7b72]Tb4b4b4.Te6edf3toIntTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3partsTff7b72[T79c0ff2Tff7b72]Tb4b4b4.Te6edf3toIntTb4b4b4(Tb4b4b4)Tb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3AndroidColorTb4b4b4.Te6edf3parseColorTb4b4b4(Te6edf3valueTb4b4b4) T8b949e// #hex or named color
Tb4b4b4}
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3IllegalArgumentExceptionTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3withTagTb4b4b4(Ta5d6ff"Ta5d6ffMapViewTa5d6ff"Tb4b4b4)Tb4b4b4.Te6edf3wTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ffUnparseable GeoJSON color: Tffd700$Te6edf3rawTa5d6ff" Tb4b4b4}
Tff7b72null
Tb4b4b4}
Tb4b4b4}

Tff7b72private Tff7b72fun Te6edf3IntTb4b4b4.Td2a8ffwithAlphaTb4b4b4(Te6edf3opacityTb4b4b4: Tffa657FloatTb4b4b4)Tb4b4b4: Tffa657Int Tff7b72= Te6edf3AndroidColorTb4b4b4.Te6edf3argbTb4b4b4(
Tb4b4b4(Te6edf3opacityTb4b4b4.Te6edf3coerceInTb4b4b4(T79c0ff0fTb4b4b4, T79c0ff1fTb4b4b4) Tff7b72* T79c0ff2T79c0ff5T79c0ff5fTb4b4b4)Tb4b4b4.Te6edf3roundToIntTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3AndroidColorTb4b4b4.Te6edf3redTb4b4b4(Tff7b72thisTb4b4b4)Tb4b4b4,
Te6edf3AndroidColorTb4b4b4.Te6edf3greenTb4b4b4(Tff7b72thisTb4b4b4)Tb4b4b4,
Te6edf3AndroidColorTb4b4b4.Te6edf3blueTb4b4b4(Tff7b72thisTb4b4b4)Tb4b4b4,
Tb4b4b4)

T8b949e// endregion

T8b949e// region --- Utilities ---

Tff7b72internal Tff7b72fun Td2a8ffconvertIntToEmojiTb4b4b4(Te6edf3unicodeCodePointTb4b4b4: Tffa657IntTb4b4b4)Tb4b4b4: Tffa657String Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3unicodeCodePointTb4b4b4.Te6edf3isValidCodePointTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3w Tb4b4b4{ Ta5d6ff"Ta5d6ffInvalid unicode code point: Tffd700$Te6edf3unicodeCodePointTa5d6ff" Tb4b4b4}
Tb4b4b4}
T8b949e// waypointIconOrDefault before rendering: 0 is a valid code point, so it would otherwise render as U+0000.
Tff7b72return Te6edf3unicodeCodePointTb4b4b4.Te6edf3waypointIconOrDefaultTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3toCodePointStringTb4b4b4(Tb4b4b4)
Tb4b4b4}

T8b949e/** Converts protobuf [Position] integer coordinates to a Google Maps [LatLng]. */
Tff7b72internal Tff7b72fun Te6edf3PositionTb4b4b4.Td2a8fftoLatLngTb4b4b4(Tb4b4b4)Tb4b4b4: Te6edf3LatLng Tff7b72= Te6edf3LatLngTb4b4b4(Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3latitude_i Tff7b72?: T79c0ff0Tb4b4b4) Tff7b72* Te6edf3DEG_DTb4b4b4, Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3longitude_i Tff7b72?: T79c0ff0Tb4b4b4) Tff7b72* Te6edf3DEG_DTb4b4b4)

T8b949e/** One-shot last known location as a suspend call. Guarded by a permission check at the call site. */
Tf0883e@SuppressLintTb4b4b4(Ta5d6ff"Ta5d6ffMissingPermissionTa5d6ff"Tb4b4b4)
Tff7b72private Tff7b72suspend Tff7b72fun Te6edf3FusedLocationProviderClientTb4b4b4.Td2a8ffawaitLastLocationTb4b4b4(Tb4b4b4)Tb4b4b4: Te6edf3Location? Tff7b72= Te6edf3suspendCancellableCoroutine Tb4b4b4{ Te6edf3cont Tff7b72-Tff7b72>
T8b949e// lastLocation can throw SecurityException synchronously if permission is revoked between the compose-time
T8b949e// isGranted check and this call; treat that as "no location" rather than crashing the estimate flow.
Tff7b72try Tb4b4b4{
Te6edf3lastLocationTb4b4b4.Te6edf3addOnSuccessListener Tb4b4b4{ Te6edf3contTb4b4b4.Te6edf3resumeTb4b4b4(Tffa657itTb4b4b4) Tb4b4b4}Tb4b4b4.Te6edf3addOnFailureListener Tb4b4b4{ Te6edf3contTb4b4b4.Te6edf3resumeTb4b4b4(Tff7b72nullTb4b4b4) Tb4b4b4}
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3_Tb4b4b4: Te6edf3SecurityExceptionTb4b4b4) Tb4b4b4{
Te6edf3contTb4b4b4.Te6edf3resumeTb4b4b4(Tff7b72nullTb4b4b4)
Tb4b4b4}
Tb4b4b4}

T8b949e/** Builds a proto [BoundingBox] (degrees ×1e7) from two opposite corner taps. */
Tff7b72private Tff7b72fun Td2a8ffboundingBoxFromCornersTb4b4b4(Te6edf3aTb4b4b4: Te6edf3LatLngTb4b4b4, Te6edf3bTb4b4b4: Te6edf3LatLngTb4b4b4)Tb4b4b4: Te6edf3BoundingBox Tff7b72= Te6edf3BoundingBoxTb4b4b4(
Te6edf3longitude_west_i Tff7b72= Tb4b4b4(Te6edf3minOfTb4b4b4(Te6edf3aTb4b4b4.Te6edf3longitudeTb4b4b4, Te6edf3bTb4b4b4.Te6edf3longitudeTb4b4b4) Tff7b72/ Te6edf3DEG_DTb4b4b4)Tb4b4b4.Te6edf3toIntTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3latitude_south_i Tff7b72= Tb4b4b4(Te6edf3minOfTb4b4b4(Te6edf3aTb4b4b4.Te6edf3latitudeTb4b4b4, Te6edf3bTb4b4b4.Te6edf3latitudeTb4b4b4) Tff7b72/ Te6edf3DEG_DTb4b4b4)Tb4b4b4.Te6edf3toIntTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3longitude_east_i Tff7b72= Tb4b4b4(Te6edf3maxOfTb4b4b4(Te6edf3aTb4b4b4.Te6edf3longitudeTb4b4b4, Te6edf3bTb4b4b4.Te6edf3longitudeTb4b4b4) Tff7b72/ Te6edf3DEG_DTb4b4b4)Tb4b4b4.Te6edf3toIntTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3latitude_north_i Tff7b72= Tb4b4b4(Te6edf3maxOfTb4b4b4(Te6edf3aTb4b4b4.Te6edf3latitudeTb4b4b4, Te6edf3bTb4b4b4.Te6edf3latitudeTb4b4b4) Tff7b72/ Te6edf3DEG_DTb4b4b4)Tb4b4b4.Te6edf3toIntTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4)

T8b949e// endregion

T8b949e/** A shared [MapBounds] as the box the Google map wants. */
Tff7b72private Tff7b72fun Te6edf3MapBoundsTb4b4b4.Td2a8fftoLatLngBoundsTb4b4b4(Tb4b4b4)Tb4b4b4: Te6edf3LatLngBounds Tff7b72= Te6edf3LatLngBoundsTb4b4b4(Te6edf3LatLngTb4b4b4(Te6edf3southTb4b4b4, Te6edf3westTb4b4b4)Tb4b4b4, Te6edf3LatLngTb4b4b4(Te6edf3northTb4b4b4, Te6edf3eastTb4b4b4)Tb4b4b4)

Served by rngit 1.5.2 - Generated in 0.34s